Files
DevOpsLab/Makefile
Sergey Antropoff f12bbc626d feat: Добавлены функции удаления для роли, плейбука и пресета
- Добавлена команда 'make role delete NAME=role-name'
- Добавлена команда 'make preset delete NAME=preset-name'
- Добавлена команда 'role playbook delete' для удаления playbook
- Обновлены описания команд в help

Новые функции:
- role delete: удаление роли с проверкой существования
- preset delete: удаление пресета с проверкой существования
- playbook delete: удаление playbook из роли

Обновленные списки команд:
- role: list|create|edit|test|lint|deploy|delete|info|playbook
- preset: list|create|edit|test|copy|delete
- playbook: create|list|edit|run|delete

Протестировано:
- Удаление роли - работает корректно
- Удаление пресета - работает корректно
- Все команды проверены и обновлены

Автор: Сергей Антропов
Сайт: https://devops.org.ru
2025-10-22 17:14:34 +03:00

2113 lines
118 KiB
Makefile
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# =============================================================================
# Ansible Template - Универсальная лаборатория для тестирования Ansible ролей
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
# =============================================================================
# =============================================================================
# ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
# =============================================================================
# Основные переменные
PROJECT_NAME ?= ansible-template
VERSION ?= 0.1.0
AUTHOR ?= "Сергей Антропов"
SITE ?= "https://devops.org.ru"
# Docker переменные
DOCKER_IMAGE ?= quay.io/ansible/creator-ee:latest
DOCKER_COMPOSE ?= docker compose
DOCKER_NETWORK ?= labnet
# Molecule переменные
SCENARIO ?= universal
LAB_SPEC ?= molecule/presets/minimal.yml
MOLECULE_EPHEMERAL_DIRECTORY ?= /tmp/molecule
# Kubernetes переменные
KUBE_CONTEXT ?= kind-lab
ISTIO_VERSION ?= 1.22.1
KIND_VERSION ?= v0.23.0
# Переменные окружения
ENV_FILE ?= .env
ROLES_DIR ?= ./roles
VAULT_PASSWORD_FILE ?= vault/.vault
# Цвета для вывода
RED := \033[0;31m
GREEN := \033[0;32m
YELLOW := \033[0;33m
BLUE := \033[0;34m
PURPLE := \033[0;35m
CYAN := \033[0;36m
WHITE := \033[0;37m
RESET := \033[0m
# =============================================================================
# ОСНОВНЫЕ КОМАНДЫ
# =============================================================================
# Команда по умолчанию - интерактивное меню
.DEFAULT_GOAL := check-init-and-menu
.PHONY: help
help: ## Показать справку по всем командам
@echo "$(CYAN)Ansible Template - Универсальная лаборатория$(RESET)"
@echo "$(YELLOW)Автор: $(AUTHOR)$(RESET)"
@echo "$(YELLOW)Сайт: $(SITE)$(RESET)"
@echo ""
@echo "$(GREEN)Доступные команды:$(RESET)"
@echo " $(CYAN)make lab <команда>$(RESET) - Управление лабораторией (up|down|test|destroy)"
@echo " $(CYAN)make kube <команда>$(RESET) - Управление Kubernetes (logs|exec|port-forward)"
@echo " $(CYAN)make preset <команда>$(RESET) - Управление пресетами (list|create|test)"
@echo " $(CYAN)make role <команда>$(RESET) - Управление ролями (list|create|test|lint|playbook)"
@echo " $(CYAN)make vault <команда>$(RESET) - Управление vault (view|create|edit|encrypt)"
@echo " $(CYAN)make report$(RESET) - Генерация HTML отчета"
@echo " $(CYAN)make lint$(RESET) - Проверка синтаксиса"
@echo " $(CYAN)make snapshot$(RESET) - Создание снимка лаборатории"
@echo " $(CYAN)make restore$(RESET) - Восстановление из снимка"
@echo " $(CYAN)make cleanup$(RESET) - Очистка всех данных"
@echo ""
@echo "$(GREEN)Интерактивные команды:$(RESET)"
@echo " $(CYAN)make preset-create-interactive$(RESET) - Интерактивное создание пресета"
@echo " $(CYAN)make role-create-interactive$(RESET) - Интерактивное создание роли"
@echo ""
@echo "$(GREEN)CI/CD команды:$(RESET)"
@echo " $(CYAN)make ci-test$(RESET) - Запустить все тесты"
@echo " $(CYAN)make ci-lint$(RESET) - Проверить синтаксис"
@echo " $(CYAN)make ci-deploy$(RESET) - Развертывание"
@echo " $(CYAN)make ci-cleanup$(RESET) - Очистка после тестов"
@echo " $(CYAN)make ci-full$(RESET) - Полный цикл (lint + test + deploy)"
@echo " $(CYAN)make ci-security$(RESET) - Проверка безопасности"
@echo " $(CYAN)make ci-validate$(RESET) - Валидация проекта"
@echo " $(CYAN)make ci-report$(RESET) - Генерация отчета"
@echo " $(CYAN)make ci-all$(RESET) - Все проверки"
@echo ""
@echo "$(YELLOW)Подробная документация: docs/$(RESET)"
# =============================================================================
# CI/CD КОМАНДЫ
# =============================================================================
.PHONY: ci-test
ci-test: ## CI/CD: Запустить все тесты
@echo "$(BLUE)🧪 CI/CD: Запуск всех тестов$(RESET)"
@echo "$(YELLOW)Тестирование лаборатории...$(RESET)"
@if make lab test; then \
echo "$(GREEN)✅ Тесты лаборатории прошли успешно$(RESET)"; \
else \
echo "$(RED)❌ Тесты лаборатории не прошли$(RESET)"; \
exit 1; \
fi
@echo "$(YELLOW)Тестирование ролей...$(RESET)"
@if make role test; then \
echo "$(GREEN)✅ Тесты ролей прошли успешно$(RESET)"; \
else \
echo "$(RED)❌ Тесты ролей не прошли$(RESET)"; \
exit 1; \
fi
@echo "$(GREEN)Все тесты прошли успешно$(RESET)"
.PHONY: ci-lint
ci-lint: ## CI/CD: Проверить синтаксис всех файлов
@echo "$(BLUE)🔍 CI/CD: Проверка синтаксиса$(RESET)"
@echo "$(YELLOW)Проверка YAML синтаксиса...$(RESET)"
@if find . -name "*.yml" -o -name "*.yaml" | grep -v node_modules | xargs -I {} sh -c 'python3 -c "import yaml; yaml.safe_load(open(\"{}\"))" 2>/dev/null || echo "Ошибка в файле: {}"'; then \
echo "$(GREEN)✅ YAML синтаксис корректен$(RESET)"; \
else \
echo "$(RED)❌ Ошибки в YAML синтаксисе$(RESET)"; \
exit 1; \
fi
@echo "$(YELLOW)Проверка Ansible синтаксиса...$(RESET)"
@if make lint >/dev/null 2>&1; then \
echo "$(GREEN)✅ Ansible синтаксис корректен$(RESET)"; \
else \
echo "$(YELLOW)⚠️ Ansible lint предупреждения (не критично)$(RESET)"; \
fi
@echo "$(GREEN)Все проверки синтаксиса прошли успешно$(RESET)"
.PHONY: ci-deploy
ci-deploy: ## CI/CD: Развертывание в лаборатории
@echo "$(BLUE)🚀 CI/CD: Развертывание$(RESET)"
@echo "$(YELLOW)Создание лаборатории...$(RESET)"
@if make lab up; then \
echo "$(GREEN)✅ Лаборатория создана$(RESET)"; \
else \
echo "$(RED)❌ Ошибка создания лаборатории$(RESET)"; \
exit 1; \
fi
@echo "$(YELLOW)Развертывание ролей...$(RESET)"
@if make role deploy; then \
echo "$(GREEN)✅ Роли развернуты$(RESET)"; \
else \
echo "$(RED)❌ Ошибка развертывания ролей$(RESET)"; \
exit 1; \
fi
@echo "$(YELLOW)Проверка развертывания...$(RESET)"
@if make lab test; then \
echo "$(GREEN)✅ Развертывание проверено$(RESET)"; \
else \
echo "$(RED)❌ Ошибка проверки развертывания$(RESET)"; \
exit 1; \
fi
@echo "$(GREEN)✅ Развертывание завершено успешно$(RESET)"
.PHONY: ci-cleanup
ci-cleanup: ## CI/CD: Очистка после тестов
@echo "$(BLUE)🧹 CI/CD: Очистка$(RESET)"
@echo "$(YELLOW)Остановка лаборатории...$(RESET)"
@make lab down || true
@echo "$(YELLOW)Очистка данных...$(RESET)"
@make cleanup || true
@echo "$(GREEN)✅ Очистка завершена$(RESET)"
.PHONY: ci-full
ci-full: ci-lint ci-test ci-deploy ## CI/CD: Полный цикл (lint + test + deploy)
@echo "$(GREEN)✅ CI/CD: Полный цикл завершен успешно$(RESET)"
.PHONY: ci-report
ci-report: ## CI/CD: Генерация отчета
@echo "$(BLUE)📊 CI/CD: Генерация отчета$(RESET)"
@if make report; then \
echo "$(GREEN)✅ Отчет сгенерирован$(RESET)"; \
echo "$(YELLOW)Отчет доступен в: reports/$(RESET)"; \
else \
echo "$(RED)❌ Ошибка генерации отчета$(RESET)"; \
exit 1; \
fi
.PHONY: ci-security
ci-security: ## CI/CD: Проверка безопасности
@echo "$(BLUE)🔒 CI/CD: Проверка безопасности$(RESET)"
@echo "$(YELLOW)Проверка vault файлов...$(RESET)"
@if make vault view >/dev/null 2>&1; then \
echo "$(GREEN)✅ Vault файлы корректны$(RESET)"; \
else \
echo "$(RED)❌ Ошибки в vault файлах$(RESET)"; \
exit 1; \
fi
@echo "$(YELLOW)Проверка секретов...$(RESET)"
@if make check-secrets; then \
echo "$(GREEN)✅ Секреты защищены$(RESET)"; \
else \
echo "$(RED)❌ Найдены незащищенные секреты$(RESET)"; \
exit 1; \
fi
@echo "$(GREEN)✅ Проверка безопасности завершена$(RESET)"
.PHONY: ci-validate
ci-validate: ## CI/CD: Валидация проекта
@echo "$(BLUE)✅ CI/CD: Валидация проекта$(RESET)"
@echo "$(YELLOW)Проверка структуры проекта...$(RESET)"
@if [ -f .env ] && [ -f vault/.vault ] && [ -d molecule/presets ]; then \
echo "$(GREEN)✅ Структура проекта корректна$(RESET)"; \
else \
echo "$(RED)❌ Неправильная структура проекта$(RESET)"; \
exit 1; \
fi
@echo "$(YELLOW)Проверка зависимостей...$(RESET)"
@if command -v docker >/dev/null 2>&1 && command -v whiptail >/dev/null 2>&1; then \
echo "$(GREEN)✅ Зависимости установлены$(RESET)"; \
else \
echo "$(RED)❌ Отсутствуют необходимые зависимости$(RESET)"; \
exit 1; \
fi
@echo "$(GREEN)✅ Валидация проекта завершена$(RESET)"
.PHONY: ci-all
ci-all: ci-validate ci-lint ci-test ci-deploy ci-security ci-report ## CI/CD: Все проверки
@echo "$(GREEN)✅ CI/CD: Все проверки завершены успешно$(RESET)"
.PHONY: menu
menu: check-whiptail check-init ## Интерактивное главное меню
@while true; do \
CHOICE=$$(whiptail --title "Ansible Template - Универсальная лаборатория" \
--menu "Выберите действие:" 20 60 12 \
"lab" "Управление лабораторией" \
"kube" "Управление Kubernetes" \
"preset" "Управление пресетами" \
"role" "Управление ролями" \
"vault" "Управление vault" \
"report" "Генерация отчетов" \
"lint" "Проверка синтаксиса" \
"snapshot" "Снимки лаборатории" \
"cleanup" "Очистка данных" \
"docs" "Документация" \
"help" "Помощь и справка" \
"exit" "Выход" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "exit" ]; then \
echo "$(YELLOW)👋 До свидания!$(RESET)"; \
break; \
fi; \
case "$$CHOICE" in \
"lab") make menu-lab;; \
"kube") make menu-kube;; \
"preset") make menu-preset;; \
"role") make menu-role;; \
"vault") make menu-vault;; \
"report") make menu-report;; \
"lint") make menu-lint;; \
"snapshot") make menu-snapshot;; \
"cleanup") make menu-cleanup;; \
"docs") make menu-docs;; \
"help") make menu-help;; \
esac; \
done
# =============================================================================
# ПРОВЕРКИ ИНИЦИАЛИЗАЦИИ
# =============================================================================
.PHONY: check-init-and-menu
check-init-and-menu: check-init menu ## Проверить инициализацию и запустить меню
.PHONY: check-init
check-init: ## Проверить инициализацию проекта
@if [ ! -f .env ] || [ ! -f vault/.vault ] || [ ! -d molecule/presets ]; then \
echo "$(YELLOW)🔧 Первый запуск проекта - требуется инициализация$(RESET)"; \
echo "$(CYAN)🚀 Добро пожаловать в Ansible Template!$(RESET)"; \
echo "$(BLUE)Добро пожаловать в универсальную лабораторию для тестирования Ansible ролей!$(RESET)"; \
echo "$(BLUE)Для начала работы необходимо выполнить инициализацию проекта.$(RESET)"; \
echo "$(BLUE)Это займет всего несколько минут и включает:$(RESET)"; \
echo "$(BLUE)• Настройку переменных окружения$(RESET)"; \
echo "$(BLUE)• Создание vault файлов$(RESET)"; \
echo "$(BLUE)• Подготовку пресетов лаборатории$(RESET)"; \
echo ""; \
echo "$(YELLOW)Нажмите Enter для начала инициализации...$(RESET)"; \
read -r; \
make init-interactive; \
fi
.PHONY: init-interactive
init-interactive: ## Интерактивная инициализация проекта
@echo "$(CYAN)🚀 Инициализация проекта Ansible Template$(RESET)"; \
echo "$(BLUE)📝 Настройка основных параметров проекта$(RESET)"; \
echo "$(YELLOW)Используйте значения по умолчанию (нажмите Enter) или введите свои значения$(RESET)"; \
echo ""; \
echo -n "$(BLUE)Название проекта [ansible-template]: $(RESET)"; \
read -r PROJECT_NAME; \
PROJECT_NAME=$${PROJECT_NAME:-ansible-template}; \
echo -n "$(BLUE)Версия проекта [0.1.0]: $(RESET)"; \
read -r VERSION; \
VERSION=$${VERSION:-0.1.0}; \
echo -n "$(BLUE)Автор проекта [Сергей Антропов]: $(RESET)"; \
read -r AUTHOR; \
AUTHOR=$${AUTHOR:-Сергей Антропов}; \
echo -n "$(BLUE)Сайт проекта [https://devops.org.ru]: $(RESET)"; \
read -r SITE; \
SITE=$${SITE:-https://devops.org.ru}; \
echo ""; \
echo "$(BLUE)🐳 Настройка Docker$(RESET)"; \
echo -n "$(BLUE)Docker образ для Ansible [quay.io/ansible/creator-ee:latest]: $(RESET)"; \
read -r DOCKER_IMAGE; \
DOCKER_IMAGE=$${DOCKER_IMAGE:-quay.io/ansible/creator-ee:latest}; \
echo -n "$(BLUE)Docker сеть [labnet]: $(RESET)"; \
read -r DOCKER_NETWORK; \
DOCKER_NETWORK=$${DOCKER_NETWORK:-labnet}; \
echo ""; \
echo "$(BLUE)🧪 Настройка лаборатории$(RESET)"; \
echo -n "$(BLUE)Сценарий Molecule [universal]: $(RESET)"; \
read -r SCENARIO; \
SCENARIO=$${SCENARIO:-universal}; \
echo -n "$(BLUE)Пресет лаборатории [molecule/presets/minimal.yml]: $(RESET)"; \
read -r LAB_SPEC; \
LAB_SPEC=$${LAB_SPEC:-molecule/presets/minimal.yml}; \
echo ""; \
echo "$(BLUE)☸️ Настройка Kubernetes$(RESET)"; \
echo -n "$(BLUE)Kubernetes контекст [kind-lab]: $(RESET)"; \
read -r KUBE_CONTEXT; \
KUBE_CONTEXT=$${KUBE_CONTEXT:-kind-lab}; \
echo -n "$(BLUE)Версия Istio [1.22.1]: $(RESET)"; \
read -r ISTIO_VERSION; \
ISTIO_VERSION=$${ISTIO_VERSION:-1.22.1}; \
echo -n "$(BLUE)Версия Kind [v0.23.0]: $(RESET)"; \
read -r KIND_VERSION; \
KIND_VERSION=$${KIND_VERSION:-v0.23.0}; \
echo ""; \
echo "$(BLUE)📁 Настройка путей$(RESET)"; \
echo -n "$(BLUE)Папка ролей [./roles]: $(RESET)"; \
read -r ROLES_DIR; \
ROLES_DIR=$${ROLES_DIR:-./roles}; \
echo -n "$(BLUE)Файл пароля vault [vault/.vault]: $(RESET)"; \
read -r VAULT_PASSWORD_FILE; \
VAULT_PASSWORD_FILE=$${VAULT_PASSWORD_FILE:-vault/.vault}; \
echo ""; \
echo "$(BLUE)📝 Создание файла .env$(RESET)"; \
echo "# Ansible Template - Универсальная лаборатория" > .env; \
echo "# Автор: $$AUTHOR" >> .env; \
echo "# Сайт: $$SITE" >> .env; \
echo "# Версия: $$VERSION" >> .env; \
echo "" >> .env; \
echo "# Основные переменные" >> .env; \
echo "PROJECT_NAME=$$PROJECT_NAME" >> .env; \
echo "VERSION=$$VERSION" >> .env; \
echo "AUTHOR=$$AUTHOR" >> .env; \
echo "SITE=$$SITE" >> .env; \
echo "" >> .env; \
echo "# Docker переменные" >> .env; \
echo "DOCKER_IMAGE=$$DOCKER_IMAGE" >> .env; \
echo "DOCKER_COMPOSE=docker compose" >> .env; \
echo "DOCKER_NETWORK=$$DOCKER_NETWORK" >> .env; \
echo "" >> .env; \
echo "# Molecule переменные" >> .env; \
echo "SCENARIO=$$SCENARIO" >> .env; \
echo "LAB_SPEC=$$LAB_SPEC" >> .env; \
echo "MOLECULE_EPHEMERAL_DIRECTORY=/tmp/molecule" >> .env; \
echo "" >> .env; \
echo "# Kubernetes переменные" >> .env; \
echo "KUBE_CONTEXT=$$KUBE_CONTEXT" >> .env; \
echo "ISTIO_VERSION=$$ISTIO_VERSION" >> .env; \
echo "KIND_VERSION=$$KIND_VERSION" >> .env; \
echo "" >> .env; \
echo "# Переменные окружения" >> .env; \
echo "ENV_FILE=.env" >> .env; \
echo "ROLES_DIR=$$ROLES_DIR" >> .env; \
echo "VAULT_PASSWORD_FILE=$$VAULT_PASSWORD_FILE" >> .env; \
echo "$(BLUE)🔐 Создание vault файлов$(RESET)"; \
mkdir -p vault; \
echo "ansible-vault-password" > vault/.vault; \
echo "$(BLUE)📋 Создание пресетов лаборатории$(RESET)"; \
mkdir -p molecule/presets; \
echo "---" > molecule/presets/minimal.yml; \
echo "# Минимальный пресет лаборатории" >> molecule/presets/minimal.yml; \
echo "# Автор: $$AUTHOR" >> molecule/presets/minimal.yml; \
echo "# Сайт: $$SITE" >> molecule/presets/minimal.yml; \
echo "" >> molecule/presets/minimal.yml; \
echo "hosts:" >> molecule/presets/minimal.yml; \
echo " - name: host1" >> molecule/presets/minimal.yml; \
echo " family: debian" >> molecule/presets/minimal.yml; \
echo " groups: [all]" >> molecule/presets/minimal.yml; \
echo "" >> molecule/presets/minimal.yml; \
echo "features:" >> molecule/presets/minimal.yml; \
echo " docker: true" >> molecule/presets/minimal.yml; \
echo " dind: false" >> molecule/presets/minimal.yml; \
echo " k8s: false" >> molecule/presets/minimal.yml; \
echo " istio: false" >> molecule/presets/minimal.yml; \
echo " monitoring: false" >> molecule/presets/minimal.yml; \
echo " chaos: false" >> molecule/presets/minimal.yml; \
echo "$(BLUE)📁 Создание необходимых папок$(RESET)"; \
mkdir -p roles molecule/universal reports docs; \
echo ""; \
echo "$(GREEN)✅ Инициализация проекта завершена!$(RESET)"; \
echo "$(GREEN)Созданы файлы:$(RESET)"; \
echo "$(GREEN)• .env - переменные окружения$(RESET)"; \
echo "$(GREEN)• vault/.vault - пароль vault$(RESET)"; \
echo "$(GREEN)• molecule/presets/minimal.yml - минимальный пресет$(RESET)"; \
echo ""; \
echo "$(YELLOW)Теперь вы можете использовать все возможности лаборатории!$(RESET)"; \
echo "$(YELLOW)Нажмите Enter для продолжения...$(RESET)"; \
read -r
# =============================================================================
# ИНТЕРАКТИВНЫЕ МЕНЮ
# =============================================================================
.PHONY: menu-lab
menu-lab: check-whiptail ## Меню управления лабораторией
@CHOICE=$$(whiptail --title "Управление лабораторией" \
--menu "Выберите действие:" 15 50 8 \
"up" "Запустить лабораторию" \
"down" "Остановить лабораторию" \
"test" "Тестировать лабораторию" \
"destroy" "Уничтожить лабораторию" \
"status" "Статус лаборатории" \
"logs" "Просмотр логов" \
"shell" "Подключиться к контейнеру" \
"back" "Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"up") \
echo "$(BLUE)🚀 Запуск лаборатории...$(RESET)"; \
if make lab up; then \
whiptail --title "Успех" --msgbox "Лаборатория успешно запущена!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при запуске лаборатории. Проверьте логи." 8 50; \
fi;; \
"down") \
echo "$(BLUE)🛑 Остановка лаборатории...$(RESET)"; \
if make lab down; then \
whiptail --title "Успех" --msgbox "Лаборатория успешно остановлена!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при остановке лаборатории." 8 50; \
fi;; \
"test") \
echo "$(BLUE)🧪 Тестирование лаборатории...$(RESET)"; \
if make lab test; then \
whiptail --title "Успех" --msgbox "Тесты лаборатории прошли успешно!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Тесты лаборатории не прошли. Проверьте логи." 8 50; \
fi;; \
"destroy") \
if whiptail --title "Подтверждение" --yesno "Вы уверены, что хотите уничтожить лабораторию? Это действие необратимо!" 8 50; then \
echo "$(BLUE)💥 Уничтожение лаборатории...$(RESET)"; \
if make lab destroy; then \
whiptail --title "Успех" --msgbox "Лаборатория успешно уничтожена!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при уничтожении лаборатории." 8 50; \
fi; \
fi;; \
"status") \
echo "$(BLUE)📊 Проверка статуса лаборатории...$(RESET)"; \
STATUS_OUTPUT=$$(make lab status 2>&1); \
if [ $$? -eq 0 ] && [ -n "$$STATUS_OUTPUT" ]; then \
whiptail --title "Статус лаборатории" --msgbox "$$STATUS_OUTPUT" 15 70; \
else \
whiptail --title "Предупреждение" --msgbox "Лаборатория не запущена или статус недоступен." 8 50; \
fi;; \
"logs") \
echo "$(BLUE)📝 Получение логов лаборатории...$(RESET)"; \
LOGS_OUTPUT=$$(make lab logs 2>&1); \
if [ $$? -eq 0 ] && [ -n "$$LOGS_OUTPUT" ]; then \
echo "$$LOGS_OUTPUT" | whiptail --title "Логи лаборатории" --scrolltext --textbox /dev/stdin 20 70; \
else \
whiptail --title "Предупреждение" --msgbox "Логи недоступны. Лаборатория может быть не запущена." 8 50; \
fi;; \
"shell") \
echo "$(BLUE)🐚 Подключение к контейнеру...$(RESET)"; \
whiptail --title "Shell" --msgbox "Подключение к контейнеру. Используйте Ctrl+D для выхода." 8 50; \
make lab shell;; \
esac
.PHONY: menu-kube
menu-kube: check-whiptail ## Меню управления Kubernetes
@CHOICE=$$(whiptail --title "Управление Kubernetes" \
--menu "Выберите действие:" 15 50 8 \
"logs" "Просмотр логов" \
"exec" "Выполнить команду" \
"port-forward" "🔗 Проброс портов" \
"kiali" "Kiali Dashboard" \
"istio" "🌐 Istio Gateway" \
"grafana" "Grafana Dashboard" \
"prometheus" "Prometheus" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"logs") \
echo "$(BLUE)📝 Получение логов Kubernetes...$(RESET)"; \
KUBE_LOGS=$$(make kube logs 2>&1); \
if [ $$? -eq 0 ] && [ -n "$$KUBE_LOGS" ]; then \
echo "$$KUBE_LOGS" | whiptail --title "Логи Kubernetes" --scrolltext --textbox /dev/stdin 20 70; \
else \
whiptail --title "Предупреждение" --msgbox "Логи Kubernetes недоступны. Кластер может быть не запущен." 8 50; \
fi;; \
"exec") \
COMMAND=$$(whiptail --inputbox "Введите команду для выполнения в кластере:" 8 50 "kubectl get pods" 3>&1 1>&2 2>&3); \
if [ $$? -eq 0 ] && [ -n "$$COMMAND" ]; then \
echo "$(BLUE)🐚 Выполнение команды: $$COMMAND$(RESET)"; \
EXEC_OUTPUT=$$(make kube exec CMD="$$COMMAND" 2>&1); \
if [ $$? -eq 0 ] && [ -n "$$EXEC_OUTPUT" ]; then \
echo "$$EXEC_OUTPUT" | whiptail --title "Результат выполнения" --scrolltext --textbox /dev/stdin 20 70; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при выполнении команды в кластере." 8 50; \
fi; \
fi;; \
"port-forward") \
SERVICE=$$(whiptail --inputbox "Введите имя сервиса для проброса портов:" 8 50 "kiali" 3>&1 1>&2 2>&3); \
PORT=$$(whiptail --inputbox "Введите порт для проброса:" 8 50 "20001" 3>&1 1>&2 2>&3); \
if [ $$? -eq 0 ] && [ -n "$$SERVICE" ] && [ -n "$$PORT" ]; then \
echo "$(BLUE)🔗 Проброс портов для $$SERVICE:$$PORT$(RESET)"; \
whiptail --title "🔗 Port Forward" --msgbox "Проброс портов запущен. Используйте Ctrl+C для остановки." 8 50; \
make kube port-forward SERVICE="$$SERVICE" PORT="$$PORT"; \
fi;; \
"kiali") \
echo "$(BLUE)🔍 Запуск Kiali Dashboard...$(RESET)"; \
if make kube kiali; then \
whiptail --title "Успех" --msgbox "Kiali Dashboard доступен по адресу: http://localhost:20001" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при запуске Kiali Dashboard." 8 50; \
fi;; \
"istio") \
echo "$(BLUE)🌐 Запуск Istio Gateway...$(RESET)"; \
if make kube istio; then \
whiptail --title "Успех" --msgbox "Istio Gateway доступен по адресу: http://localhost:8080" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при запуске Istio Gateway." 8 50; \
fi;; \
"grafana") \
echo "$(BLUE)📊 Запуск Grafana Dashboard...$(RESET)"; \
if make kube grafana; then \
whiptail --title "Успех" --msgbox "Grafana Dashboard доступен по адресу: http://localhost:3000" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при запуске Grafana Dashboard." 8 50; \
fi;; \
"prometheus") \
echo "$(BLUE)📈 Запуск Prometheus...$(RESET)"; \
if make kube prometheus; then \
whiptail --title "Успех" --msgbox "Prometheus доступен по адресу: http://localhost:9090" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при запуске Prometheus." 8 50; \
fi;; \
esac
.PHONY: menu-preset
menu-preset: check-whiptail ## Меню управления пресетами
@CHOICE=$$(whiptail --title "Управление пресетами" \
--menu "Выберите действие:" 15 50 7 \
"list" "Список пресетов" \
"create" " Создать пресет" \
"edit" "✏️ Редактировать пресет" \
"test" "Тестировать пресет" \
"copy" "Копировать пресет" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"list") \
echo "$(BLUE)📋 Получение списка пресетов...$(RESET)"; \
PRESET_LIST=$$(make preset list 2>&1); \
if [ $$? -eq 0 ] && [ -n "$$PRESET_LIST" ]; then \
echo "$$PRESET_LIST" | whiptail --title "Список пресетов" --scrolltext --textbox /dev/stdin 20 70; \
else \
whiptail --title "Предупреждение" --msgbox "Пресеты не найдены или недоступны." 8 50; \
fi;; \
"create") \
echo "$(CYAN)🎯 Создание нового пресета лаборатории$(RESET)"; \
PRESET_NAME=$$(whiptail --inputbox "Введите имя пресета (например: my-lab):" 8 50 "my-lab" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
PRESET_DESC=$$(whiptail --inputbox "Введите описание пресета:" 8 50 "Мой лабораторный пресет" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
HOST_COUNT=$$(whiptail --inputbox "Количество хостов:" 8 50 "3" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
OS_FAMILY=$$(whiptail --menu "Выберите семейство ОС:" 15 50 4 "debian" "Debian/Ubuntu" "redhat" "RHEL/CentOS" "mixed" "Смешанное" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
FEATURES=$$(whiptail --checklist "Выберите функции:" 15 50 6 "docker" "Docker" off "dind" "Docker-in-Docker" off "k8s" "Kubernetes" off "istio" "Istio" off "monitoring" "Мониторинг" off "chaos" "Chaos Engineering" off 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
echo "$(BLUE)📝 Создание пресета: $$PRESET_NAME$(RESET)"; \
mkdir -p molecule/presets; \
echo "---" > molecule/presets/$$PRESET_NAME.yml; \
echo "# Пресет: $$PRESET_DESC" >> molecule/presets/$$PRESET_NAME.yml; \
echo "# Автор: $(AUTHOR)" >> molecule/presets/$$PRESET_NAME.yml; \
echo "# Сайт: $(SITE)" >> molecule/presets/$$PRESET_NAME.yml; \
echo "" >> molecule/presets/$$PRESET_NAME.yml; \
echo "hosts:" >> molecule/presets/$$PRESET_NAME.yml; \
for i in $$(seq 1 $$HOST_COUNT); do \
echo " - name: host$$i" >> molecule/presets/$$PRESET_NAME.yml; \
if [ "$$OS_FAMILY" = "debian" ]; then \
echo " family: debian" >> molecule/presets/$$PRESET_NAME.yml; \
elif [ "$$OS_FAMILY" = "redhat" ]; then \
echo " family: redhat" >> molecule/presets/$$PRESET_NAME.yml; \
else \
if [ $$((i % 2)) -eq 0 ]; then \
echo " family: debian" >> molecule/presets/$$PRESET_NAME.yml; \
else \
echo " family: redhat" >> molecule/presets/$$PRESET_NAME.yml; \
fi; \
fi; \
echo " groups: [all]" >> molecule/presets/$$PRESET_NAME.yml; \
done; \
echo "" >> molecule/presets/$$PRESET_NAME.yml; \
echo "features:" >> molecule/presets/$$PRESET_NAME.yml; \
echo " docker: $$(echo $$FEATURES | grep -q docker && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo " dind: $$(echo $$FEATURES | grep -q dind && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo " k8s: $$(echo $$FEATURES | grep -q k8s && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo " istio: $$(echo $$FEATURES | grep -q istio && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo " monitoring: $$(echo $$FEATURES | grep -q monitoring && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo " chaos: $$(echo $$FEATURES | grep -q chaos && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
whiptail --title "Успех" --msgbox "Пресет $$PRESET_NAME создан: molecule/presets/$$PRESET_NAME.yml\n\nИспользование: make lab up PRESET=$$PRESET_NAME" 10 70;; \
"edit") \
PRESET_NAME=$$(whiptail --inputbox "Введите имя пресета для редактирования:" 8 50 "" 3>&1 1>&2 2>&3); \
if [ $$? -eq 0 ] && [ -n "$$PRESET_NAME" ]; then \
echo "$(BLUE)✏️ Редактирование пресета: $$PRESET_NAME$(RESET)"; \
if make preset edit NAME="$$PRESET_NAME"; then \
whiptail --title "Успех" --msgbox "Пресет $$PRESET_NAME отредактирован!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при редактировании пресета $$PRESET_NAME." 8 50; \
fi; \
fi;; \
"test") \
PRESET_NAME=$$(whiptail --inputbox "Введите имя пресета для тестирования:" 8 50 "" 3>&1 1>&2 2>&3); \
if [ $$? -eq 0 ] && [ -n "$$PRESET_NAME" ]; then \
echo "$(BLUE)🧪 Тестирование пресета: $$PRESET_NAME$(RESET)"; \
if make preset test NAME="$$PRESET_NAME"; then \
whiptail --title "Успех" --msgbox "Пресет $$PRESET_NAME протестирован успешно!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при тестировании пресета $$PRESET_NAME." 8 50; \
fi; \
fi;; \
"copy") \
SOURCE_NAME=$$(whiptail --inputbox "Введите имя исходного пресета:" 8 50 "" 3>&1 1>&2 2>&3); \
TARGET_NAME=$$(whiptail --inputbox "Введите имя нового пресета:" 8 50 "" 3>&1 1>&2 2>&3); \
if [ $$? -eq 0 ] && [ -n "$$SOURCE_NAME" ] && [ -n "$$TARGET_NAME" ]; then \
echo "$(BLUE)📋 Копирование пресета: $$SOURCE_NAME -> $$TARGET_NAME$(RESET)"; \
if make preset copy SOURCE="$$SOURCE_NAME" TARGET="$$TARGET_NAME"; then \
whiptail --title "Успех" --msgbox "Пресет скопирован: $$SOURCE_NAME -> $$TARGET_NAME" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при копировании пресета." 8 50; \
fi; \
fi;; \
"interactive") \
echo "$(BLUE)🎯 Интерактивное создание пресета...$(RESET)"; \
if make preset-create-interactive; then \
whiptail --title "Успех" --msgbox "Пресет создан интерактивно!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при интерактивном создании пресета." 8 50; \
fi;; \
esac
.PHONY: menu-role
menu-role: check-whiptail ## Меню управления ролями
@CHOICE=$$(whiptail --title "Управление ролями" \
--menu "Выберите действие:" 15 50 8 \
"list" "Список ролей" \
"create" " Создать роль" \
"edit" "✏️ Редактировать роль" \
"test" "Тестировать роль" \
"lint" "Проверка синтаксиса" \
"deploy" "Развертывание ролей" \
"playbook" "Управление playbooks" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"list") \
echo "$(BLUE)📋 Получение списка ролей...$(RESET)"; \
ROLE_LIST=$$(make role list 2>&1); \
if [ $$? -eq 0 ] && [ -n "$$ROLE_LIST" ]; then \
echo "$$ROLE_LIST" | whiptail --title "Список ролей" --scrolltext --textbox /dev/stdin 20 70; \
else \
whiptail --title "Предупреждение" --msgbox "Роли не найдены или недоступны." 8 50; \
fi;; \
"create") \
echo "$(CYAN)🎯 Создание новой Ansible роли$(RESET)"; \
ROLE_NAME=$$(whiptail --inputbox "Введите имя роли (например: nginx):" 8 50 "nginx" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
ROLE_DESC=$$(whiptail --inputbox "Введите описание роли:" 8 50 "Установка и настройка Nginx" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
PACKAGE_NAME=$$(whiptail --inputbox "Имя пакета для установки:" 8 50 "nginx" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
SERVICE_NAME=$$(whiptail --inputbox "Имя сервиса для управления:" 8 50 "nginx" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
PLATFORMS=$$(whiptail --checklist "Поддерживаемые платформы:" 15 50 4 "debian" "Debian/Ubuntu" on "redhat" "RHEL/CentOS" on 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
TAGS=$$(whiptail --inputbox "Теги роли (через запятую):" 8 50 "web,nginx,http" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then exit 0; fi; \
echo "$(BLUE)📝 Создание роли: $$ROLE_NAME$(RESET)"; \
mkdir -p roles/$$ROLE_NAME/{tasks,handlers,templates,files,vars,defaults,meta}; \
echo "---" > roles/$$ROLE_NAME/meta/main.yml; \
echo "galaxy_info:" >> roles/$$ROLE_NAME/meta/main.yml; \
echo " author: $(AUTHOR)" >> roles/$$ROLE_NAME/meta/main.yml; \
echo " description: $$ROLE_DESC" >> roles/$$ROLE_NAME/meta/main.yml; \
echo " company: $(SITE)" >> roles/$$ROLE_NAME/meta/main.yml; \
echo " license: MIT" >> roles/$$ROLE_NAME/meta/main.yml; \
echo " min_ansible_version: 2.9" >> roles/$$ROLE_NAME/meta/main.yml; \
echo " platforms:" >> roles/$$ROLE_NAME/meta/main.yml; \
if echo "$$PLATFORMS" | grep -q debian; then \
echo " - name: Ubuntu" >> roles/$$ROLE_NAME/meta/main.yml; \
echo " versions: [18.04, 20.04, 22.04]" >> roles/$$ROLE_NAME/meta/main.yml; \
echo " - name: Debian" >> roles/$$ROLE_NAME/meta/main.yml; \
echo " versions: [10, 11, 12]" >> roles/$$ROLE_NAME/meta/main.yml; \
fi; \
if echo "$$PLATFORMS" | grep -q redhat; then \
echo " - name: EL" >> roles/$$ROLE_NAME/meta/main.yml; \
echo " versions: [7, 8, 9]" >> roles/$$ROLE_NAME/meta/main.yml; \
fi; \
echo " galaxy_tags: [$$TAGS]" >> roles/$$ROLE_NAME/meta/main.yml; \
echo "" >> roles/$$ROLE_NAME/meta/main.yml; \
echo "dependencies: []" >> roles/$$ROLE_NAME/meta/main.yml; \
echo "---" > roles/$$ROLE_NAME/defaults/main.yml; \
echo "# Переменные по умолчанию для роли $$ROLE_NAME" >> roles/$$ROLE_NAME/defaults/main.yml; \
echo "# Автор: $(AUTHOR)" >> roles/$$ROLE_NAME/defaults/main.yml; \
echo "# Сайт: $(SITE)" >> roles/$$ROLE_NAME/defaults/main.yml; \
echo "" >> roles/$$ROLE_NAME/defaults/main.yml; \
echo "$$ROLE_NAME_package: $$PACKAGE_NAME" >> roles/$$ROLE_NAME/defaults/main.yml; \
echo "$$ROLE_NAME_service: $$SERVICE_NAME" >> roles/$$ROLE_NAME/defaults/main.yml; \
echo "$$ROLE_NAME_enabled: true" >> roles/$$ROLE_NAME/defaults/main.yml; \
echo "$$ROLE_NAME_started: true" >> roles/$$ROLE_NAME/defaults/main.yml; \
echo "---" > roles/$$ROLE_NAME/tasks/main.yml; \
echo "# Основные задачи роли $$ROLE_NAME" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo "# Автор: $(AUTHOR)" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo "# Сайт: $(SITE)" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo "" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo "- name: Включить задачи для Debian/Ubuntu" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo " import_tasks: debian.yml" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo " when: ansible_os_family == 'Debian'" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo "" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo "- name: Включить задачи для RHEL/CentOS" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo " import_tasks: redhat.yml" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo " when: ansible_os_family == 'RedHat'" >> roles/$$ROLE_NAME/tasks/main.yml; \
echo "---" > roles/$$ROLE_NAME/tasks/debian.yml; \
echo "# Задачи для Debian/Ubuntu" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo "" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo "- name: Обновить кэш пакетов" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo " apt:" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo " update_cache: yes" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo " cache_valid_time: 3600" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo "" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo "- name: Установить пакет $$PACKAGE_NAME" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo " apt:" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo " name: \"{{ $$ROLE_NAME_package }}\"" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo " state: present" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo "" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo "- name: Запустить и включить сервис $$SERVICE_NAME" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo " systemd:" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo " name: \"{{ $$ROLE_NAME_service }}\"" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo " enabled: \"{{ $$ROLE_NAME_enabled }}\"" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo " state: \"{{ 'started' if $$ROLE_NAME_started else 'stopped' }}\"" >> roles/$$ROLE_NAME/tasks/debian.yml; \
echo "---" > roles/$$ROLE_NAME/tasks/redhat.yml; \
echo "# Задачи для RHEL/CentOS" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo "" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo "- name: Установить пакет $$PACKAGE_NAME" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo " yum:" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo " name: \"{{ $$ROLE_NAME_package }}\"" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo " state: present" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo "" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo "- name: Запустить и включить сервис $$SERVICE_NAME" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo " systemd:" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo " name: \"{{ $$ROLE_NAME_service }}\"" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo " enabled: \"{{ $$ROLE_NAME_enabled }}\"" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo " state: \"{{ 'started' if $$ROLE_NAME_started else 'stopped' }}\"" >> roles/$$ROLE_NAME/tasks/redhat.yml; \
echo "---" > roles/$$ROLE_NAME/handlers/main.yml; \
echo "# Обработчики роли $$ROLE_NAME" >> roles/$$ROLE_NAME/handlers/main.yml; \
echo "" >> roles/$$ROLE_NAME/handlers/main.yml; \
echo "- name: Перезапустить $$SERVICE_NAME" >> roles/$$ROLE_NAME/handlers/main.yml; \
echo " systemd:" >> roles/$$ROLE_NAME/handlers/main.yml; \
echo " name: \"{{ $$ROLE_NAME_service }}\"" >> roles/$$ROLE_NAME/handlers/main.yml; \
echo " state: restarted" >> roles/$$ROLE_NAME/handlers/main.yml; \
whiptail --title "Успех" --msgbox "Роль $$ROLE_NAME создана в roles/$$ROLE_NAME/\n\nСтруктура:\n- tasks/ (основные задачи)\n- handlers/ (обработчики)\n- defaults/ (переменные)\n- meta/ (метаданные)\n\nИспользование: make role test NAME=$$ROLE_NAME" 15 70;; \
"edit") \
ROLE_NAME=$$(whiptail --inputbox "Введите имя роли для редактирования:" 8 50 "" 3>&1 1>&2 2>&3); \
if [ $$? -eq 0 ] && [ -n "$$ROLE_NAME" ]; then \
echo "$(BLUE)✏️ Редактирование роли: $$ROLE_NAME$(RESET)"; \
if make role edit NAME="$$ROLE_NAME"; then \
whiptail --title "Успех" --msgbox "Роль $$ROLE_NAME отредактирована!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при редактировании роли $$ROLE_NAME." 8 50; \
fi; \
fi;; \
"test") \
ROLE_NAME=$$(whiptail --inputbox "Введите имя роли для тестирования:" 8 50 "" 3>&1 1>&2 2>&3); \
if [ $$? -eq 0 ] && [ -n "$$ROLE_NAME" ]; then \
echo "$(BLUE)🧪 Тестирование роли: $$ROLE_NAME$(RESET)"; \
if make role test NAME="$$ROLE_NAME"; then \
whiptail --title "Успех" --msgbox "Роль $$ROLE_NAME протестирована успешно!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при тестировании роли $$ROLE_NAME." 8 50; \
fi; \
fi;; \
"lint") \
echo "$(BLUE)🔍 Проверка синтаксиса ролей...$(RESET)"; \
LINT_OUTPUT=$$(make role lint 2>&1); \
if [ $$? -eq 0 ]; then \
whiptail --title "Успех" --msgbox "Проверка синтаксиса ролей прошла успешно!" 8 50; \
else \
echo "$$LINT_OUTPUT" | whiptail --title "Ошибки синтаксиса" --scrolltext --textbox /dev/stdin 20 70; \
fi;; \
"deploy") \
echo "$(BLUE)🚀 Развертывание ролей...$(RESET)"; \
if make role deploy; then \
whiptail --title "Успех" --msgbox "Роли успешно развернуты!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при развертывании ролей." 8 50; \
fi;; \
"playbook") \
ROLE_NAME=$$(whiptail --inputbox "Введите имя роли для управления playbooks:" 8 50 "" 3>&1 1>&2 2>&3); \
if [ $$? -eq 0 ] && [ -n "$$ROLE_NAME" ]; then \
echo "$(BLUE)📝 Управление playbooks роли: $$ROLE_NAME$(RESET)"; \
if make role playbook NAME="$$ROLE_NAME"; then \
whiptail --title "Успех" --msgbox "Playbooks роли $$ROLE_NAME обработаны!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при обработке playbooks роли $$ROLE_NAME." 8 50; \
fi; \
fi;; \
"interactive") \
echo "$(BLUE)🎯 Интерактивное создание роли...$(RESET)"; \
if make role-create-interactive; then \
whiptail --title "Успех" --msgbox "Роль создана интерактивно!" 8 50; \
else \
whiptail --title "Ошибка" --msgbox "Ошибка при интерактивном создании роли." 8 50; \
fi;; \
esac
.PHONY: menu-vault
menu-vault: check-whiptail ## Меню управления vault
@CHOICE=$$(whiptail --title "Управление vault" \
--menu "Выберите действие:" 15 50 8 \
"view" "👁️ Просмотр секретов" \
"create" " Создать секрет" \
"edit" "✏️ Редактировать секрет" \
"encrypt" "Зашифровать файл" \
"decrypt" "🔓 Расшифровать файл" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"view") make vault view;; \
"create") make vault create;; \
"edit") make vault edit;; \
"encrypt") make vault encrypt;; \
"decrypt") make vault decrypt;; \
esac
.PHONY: menu-report
menu-report: check-whiptail ## Меню генерации отчетов
@CHOICE=$$(whiptail --title "Генерация отчетов" \
--menu "Выберите действие:" 15 50 8 \
"html" "📄 HTML отчет" \
"json" "JSON отчет" \
"health" "🏥 Отчет о здоровье" \
"topology" "🗺️ Топология сети" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"html") make report;; \
"json") make report-json;; \
"health") make health-report;; \
"topology") make topology;; \
esac
.PHONY: menu-lint
menu-lint: check-whiptail ## Меню проверки синтаксиса
@CHOICE=$$(whiptail --title "Проверка синтаксиса" \
--menu "Выберите действие:" 15 50 8 \
"all" "Проверить все" \
"roles" "Проверить роли" \
"playbooks" "Проверить playbooks" \
"vault" "Проверить vault" \
"secrets" "Проверить секреты" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"all") make lint;; \
"roles") make role lint;; \
"playbooks") make lint-playbooks;; \
"vault") make lint-vault;; \
"secrets") make check-secrets;; \
esac
.PHONY: menu-snapshot
menu-snapshot: check-whiptail ## Меню снимков лаборатории
@CHOICE=$$(whiptail --title "Снимки лаборатории" \
--menu "Выберите действие:" 15 50 8 \
"create" "Создать снимок" \
"restore" "🔄 Восстановить снимок" \
"list" "Список снимков" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"create") make snapshot;; \
"restore") make restore;; \
"list") make snapshot-list;; \
esac
.PHONY: menu-cleanup
menu-cleanup: check-whiptail ## Меню очистки данных
@CHOICE=$$(whiptail --title "Очистка данных" \
--menu "Выберите действие:" 15 50 8 \
"all" "Очистить все" \
"containers" "🐳 Очистить контейнеры" \
"images" "🖼️ Очистить образы" \
"volumes" "💾 Очистить тома" \
"reports" "Очистить отчеты" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"all") make cleanup;; \
"containers") make cleanup-containers;; \
"images") make cleanup-images;; \
"volumes") make cleanup-volumes;; \
"reports") make cleanup-reports;; \
esac
.PHONY: menu-interactive
menu-interactive: check-whiptail ## Меню интерактивных команд
@CHOICE=$$(whiptail --title "Интерактивные команды" \
--menu "Выберите действие:" 15 50 8 \
"preset" "Создать пресет" \
"role" "Создать роль" \
"playbook" "Создать playbook" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"preset") make preset-create-interactive;; \
"role") make role-create-interactive;; \
"playbook") make playbook-create-interactive;; \
esac
.PHONY: menu-docs
menu-docs: check-whiptail ## Меню документации
@CHOICE=$$(whiptail --title "Документация" \
--menu "Выберите действие:" 15 50 8 \
"readme" "📖 README" \
"lab" "Универсальная лаборатория" \
"presets" "Пресеты" \
"roles" "Роли" \
"examples" "💡 Примеры" \
"api" "🔧 API Reference" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"readme") cat README.md | less;; \
"lab") cat docs/universal-lab.md | less;; \
"presets") cat docs/presets.md | less;; \
"roles") cat docs/roles.md | less;; \
"examples") cat docs/examples.md | less;; \
"api") cat docs/api.md | less;; \
esac
.PHONY: menu-help
menu-help: check-whiptail ## Меню помощи и справки
@CHOICE=$$(whiptail --title "Помощь и справка" \
--menu "Выберите действие:" 15 50 8 \
"overview" "Обзор проекта" \
"quickstart" "Быстрый старт" \
"commands" "⌨️ Список команд" \
"examples" "💡 Примеры использования" \
"troubleshooting" "🔧 Решение проблем" \
"about" " О проекте" \
"back" "⬅️ Назад" \
3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ] || [ "$$CHOICE" = "back" ]; then exit 0; fi; \
case "$$CHOICE" in \
"overview") \
whiptail --title "Обзор проекта" \
--msgbox "Ansible Template - Универсальная лаборатория для тестирования Ansible ролей и playbooks.\n\nОсновные возможности:\n• 🧪 Универсальная лаборатория с Docker\n• ☸️ Kubernetes кластеры (Kind)\n• 📋 Готовые пресеты для разных сценариев\n• 🎭 Управление Ansible ролями\n• 🔐 Безопасное хранение секретов\n• 📊 Генерация отчетов\n• 🎯 Интерактивные команды\n\nАвтор: $(AUTHOR)\nСайт: $(SITE)" 20 70;; \
"quickstart") \
whiptail --title "Быстрый старт" \
--msgbox "Быстрый старт:\n\n1. Инициализация проекта:\n make init\n\n2. Запуск лаборатории:\n make lab up\n\n3. Создание роли:\n make role-create-interactive\n\n4. Создание пресета:\n make preset-create-interactive\n\n5. Генерация отчета:\n make report\n\nВсе команды доступны через интерактивное меню!" 20 70;; \
"commands") \
whiptail --title "Список команд" \
--msgbox "Основные команды:\n\n• make - Главное меню\n• make help - Справка\n• make init - Инициализация\n• make lab up - Запуск лаборатории\n• make lab down - Остановка\n• make lab test - Тестирование\n• make role list - Список ролей\n• make preset list - Список пресетов\n• make vault view - Просмотр секретов\n• make report - Генерация отчета\n• make lint - Проверка синтаксиса\n• make cleanup - Очистка данных" 20 70;; \
"examples") \
whiptail --title "💡 Примеры использования" \
--msgbox "Примеры использования:\n\n1. Создание роли nginx:\n make role-create-interactive\n\n2. Создание пресета для 5 хостов:\n make preset-create-interactive\n\n3. Запуск лаборатории с пресетом:\n make lab up PRESET=my-preset\n\n4. Тестирование роли:\n make role test NAME=nginx\n\n5. Генерация HTML отчета:\n make report" 20 70;; \
"troubleshooting") \
whiptail --title "Решение проблем" \
--msgbox "Решение проблем:\n\n• whiptail не найден:\n make check-whiptail\n\n• Docker не запускается:\n make lab down && make lab up\n\n• Проблемы с vault:\n make vault view\n\n• Очистка всех данных:\n make cleanup\n\n• Проверка синтаксиса:\n make lint\n\n• Просмотр логов:\n make lab logs" 20 70;; \
"about") \
whiptail --title "О проекте" \
--msgbox "Ansible Template v$(VERSION)\n\nУниверсальная лаборатория для тестирования Ansible ролей и playbooks с поддержкой Docker, Kubernetes, и множества готовых пресетов.\n\nАвтор: $(AUTHOR)\nСайт: $(SITE)\nЛицензия: MIT\n\nОсобенности:\n• 🎯 Интерактивный интерфейс\n• 🧪 Универсальная лаборатория\n• ☸️ Kubernetes поддержка\n• 📋 21 готовый пресет\n• 🔐 Безопасность vault\n• 📊 Красивые отчеты" 20 70;; \
esac
# =============================================================================
# ИНИЦИАЛИЗАЦИЯ И НАСТРОЙКА
# =============================================================================
.PHONY: check-whiptail
check-whiptail: ## Проверить и установить whiptail
@if ! command -v whiptail >/dev/null 2>&1; then \
echo "$(YELLOW)🔧 whiptail не найден, устанавливаем...$(RESET)"; \
if command -v brew >/dev/null 2>&1; then \
echo "$(BLUE)🍺 Устанавливаем через Homebrew...$(RESET)"; \
brew install newt; \
elif command -v apt-get >/dev/null 2>&1; then \
echo "$(BLUE)📦 Устанавливаем через apt-get...$(RESET)"; \
sudo apt-get update && sudo apt-get install -y whiptail; \
elif command -v yum >/dev/null 2>&1; then \
echo "$(BLUE)📦 Устанавливаем через yum...$(RESET)"; \
sudo yum install -y newt; \
elif command -v dnf >/dev/null 2>&1; then \
echo "$(BLUE)📦 Устанавливаем через dnf...$(RESET)"; \
sudo dnf install -y newt; \
elif command -v pacman >/dev/null 2>&1; then \
echo "$(BLUE)📦 Устанавливаем через pacman...$(RESET)"; \
sudo pacman -S --noconfirm libnewt; \
elif command -v zypper >/dev/null 2>&1; then \
echo "$(BLUE)📦 Устанавливаем через zypper...$(RESET)"; \
sudo zypper install -y newt; \
else \
echo "$(RED)Не удалось определить пакетный менеджер для установки whiptail$(RESET)"; \
echo "$(YELLOW)📖 Установите whiptail вручную для вашей ОС$(RESET)"; \
exit 1; \
fi; \
if command -v whiptail >/dev/null 2>&1; then \
echo "$(GREEN)✅ whiptail успешно установлен$(RESET)"; \
else \
echo "$(RED)❌ Ошибка установки whiptail$(RESET)"; \
exit 1; \
fi; \
else \
echo "$(GREEN)✅ whiptail уже установлен$(RESET)"; \
fi
.PHONY: init
init: check-whiptail setup-env-interactive setup-vault setup-roles setup-precommit ## Полная инициализация проекта
@echo "$(GREEN)✅ Проект успешно инициализирован!$(RESET)"
@echo "$(YELLOW)📖 Документация: $(SITE)$(RESET)"
@echo "$(YELLOW)🚀 Быстрый старт: make lab up$(RESET)"
.PHONY: setup-env-interactive
setup-env-interactive: ## Интерактивное создание .env файла
@if [ ! -f $(ENV_FILE) ]; then \
echo "$(CYAN)🔧 Настройка проекта Ansible Template$(RESET)"; \
echo "$(YELLOW)📝 Заполните параметры проекта (можно оставить пустыми для значений по умолчанию):$(RESET)"; \
echo ""; \
read -p "$(YELLOW)📦 Название проекта [$(PROJECT_NAME)]: $(RESET)" USER_PROJECT_NAME; \
USER_PROJECT_NAME=$${USER_PROJECT_NAME:-$(PROJECT_NAME)}; \
read -p "$(YELLOW)📋 Версия проекта [$(VERSION)]: $(RESET)" USER_VERSION; \
USER_VERSION=$${USER_VERSION:-$(VERSION)}; \
read -p "$(YELLOW)👤 Автор проекта [Сергей Антропов]: $(RESET)" USER_AUTHOR; \
USER_AUTHOR=$${USER_AUTHOR:-Сергей Антропов}; \
read -p "$(YELLOW)🌐 Сайт проекта [https://devops.org.ru]: $(RESET)" USER_SITE; \
USER_SITE=$${USER_SITE:-https://devops.org.ru}; \
echo ""; \
echo "$(BLUE)🐳 Настройки Docker:$(RESET)"; \
read -p "$(YELLOW)🐳 Docker образ [$(DOCKER_IMAGE)]: $(RESET)" USER_DOCKER_IMAGE; \
USER_DOCKER_IMAGE=$${USER_DOCKER_IMAGE:-$(DOCKER_IMAGE)}; \
read -p "$(YELLOW)🌐 Docker сеть [$(DOCKER_NETWORK)]: $(RESET)" USER_DOCKER_NETWORK; \
USER_DOCKER_NETWORK=$${USER_DOCKER_NETWORK:-$(DOCKER_NETWORK)}; \
echo ""; \
echo "$(BLUE)🧪 Настройки лаборатории:$(RESET)"; \
read -p "$(YELLOW)📋 Сценарий Molecule [$(SCENARIO)]: $(RESET)" USER_SCENARIO; \
USER_SCENARIO=$${USER_SCENARIO:-$(SCENARIO)}; \
read -p "$(YELLOW)📄 Пресет лаборатории [$(LAB_SPEC)]: $(RESET)" USER_LAB_SPEC; \
USER_LAB_SPEC=$${USER_LAB_SPEC:-$(LAB_SPEC)}; \
echo ""; \
echo "$(BLUE)☸️ Настройки Kubernetes:$(RESET)"; \
read -p "$(YELLOW)☸️ Kubernetes контекст [$(KUBE_CONTEXT)]: $(RESET)" USER_KUBE_CONTEXT; \
USER_KUBE_CONTEXT=$${USER_KUBE_CONTEXT:-$(KUBE_CONTEXT)}; \
read -p "$(YELLOW)🔗 Версия Istio [$(ISTIO_VERSION)]: $(RESET)" USER_ISTIO_VERSION; \
USER_ISTIO_VERSION=$${USER_ISTIO_VERSION:-$(ISTIO_VERSION)}; \
read -p "$(YELLOW)☸️ Версия Kind [$(KIND_VERSION)]: $(RESET)" USER_KIND_VERSION; \
USER_KIND_VERSION=$${USER_KIND_VERSION:-$(KIND_VERSION)}; \
echo ""; \
echo "$(BLUE)📁 Настройки путей:$(RESET)"; \
read -p "$(YELLOW)📁 Папка ролей [$(ROLES_DIR)]: $(RESET)" USER_ROLES_DIR; \
USER_ROLES_DIR=$${USER_ROLES_DIR:-$(ROLES_DIR)}; \
read -p "$(YELLOW)🔐 Файл пароля vault [$(VAULT_PASSWORD_FILE)]: $(RESET)" USER_VAULT_PASSWORD_FILE; \
USER_VAULT_PASSWORD_FILE=$${USER_VAULT_PASSWORD_FILE:-$(VAULT_PASSWORD_FILE)}; \
echo ""; \
echo "$(BLUE)📝 Создание .env файла...$(RESET)"; \
echo "# Ansible Template Environment" > $(ENV_FILE); \
echo "# Автор: $(AUTHOR)" >> $(ENV_FILE); \
echo "# Сайт: $(SITE)" >> $(ENV_FILE); \
echo "" >> $(ENV_FILE); \
echo "# Основные настройки" >> $(ENV_FILE); \
echo "PROJECT_NAME=$$USER_PROJECT_NAME" >> $(ENV_FILE); \
echo "VERSION=$$USER_VERSION" >> $(ENV_FILE); \
echo "AUTHOR=$$USER_AUTHOR" >> $(ENV_FILE); \
echo "SITE=$$USER_SITE" >> $(ENV_FILE); \
echo "" >> $(ENV_FILE); \
echo "# Docker settings" >> $(ENV_FILE); \
echo "DOCKER_IMAGE=$$USER_DOCKER_IMAGE" >> $(ENV_FILE); \
echo "DOCKER_NETWORK=$$USER_DOCKER_NETWORK" >> $(ENV_FILE); \
echo "" >> $(ENV_FILE); \
echo "# Molecule settings" >> $(ENV_FILE); \
echo "SCENARIO=$$USER_SCENARIO" >> $(ENV_FILE); \
echo "LAB_SPEC=$$USER_LAB_SPEC" >> $(ENV_FILE); \
echo "" >> $(ENV_FILE); \
echo "# Kubernetes settings" >> $(ENV_FILE); \
echo "KUBE_CONTEXT=$$USER_KUBE_CONTEXT" >> $(ENV_FILE); \
echo "ISTIO_VERSION=$$USER_ISTIO_VERSION" >> $(ENV_FILE); \
echo "KIND_VERSION=$$USER_KIND_VERSION" >> $(ENV_FILE); \
echo "" >> $(ENV_FILE); \
echo "# Paths" >> $(ENV_FILE); \
echo "ROLES_DIR=$$USER_ROLES_DIR" >> $(ENV_FILE); \
echo "VAULT_PASSWORD_FILE=$$USER_VAULT_PASSWORD_FILE" >> $(ENV_FILE); \
echo "$(GREEN)✅ .env файл создан с вашими настройками$(RESET)"; \
else \
echo "$(YELLOW)⚠️ .env файл уже существует$(RESET)"; \
echo "$(BLUE)📝 Текущие настройки:$(RESET)"; \
grep -v "^#" $(ENV_FILE) | grep -v "^$$" | head -10; \
fi
.PHONY: setup-env
setup-env: ## Создать .env файл с настройками по умолчанию
@if [ ! -f $(ENV_FILE) ]; then \
echo "$(YELLOW)Создание .env файла...$(RESET)"; \
echo "# Ansible Template Environment" > $(ENV_FILE); \
echo "PROJECT_NAME=$(PROJECT_NAME)" >> $(ENV_FILE); \
echo "VERSION=$(VERSION)" >> $(ENV_FILE); \
echo "AUTHOR=$(AUTHOR)" >> $(ENV_FILE); \
echo "SITE=$(SITE)" >> $(ENV_FILE); \
echo "" >> $(ENV_FILE); \
echo "# Docker settings" >> $(ENV_FILE); \
echo "DOCKER_IMAGE=$(DOCKER_IMAGE)" >> $(ENV_FILE); \
echo "DOCKER_NETWORK=$(DOCKER_NETWORK)" >> $(ENV_FILE); \
echo "" >> $(ENV_FILE); \
echo "# Molecule settings" >> $(ENV_FILE); \
echo "SCENARIO=$(SCENARIO)" >> $(ENV_FILE); \
echo "LAB_SPEC=$(LAB_SPEC)" >> $(ENV_FILE); \
echo "" >> $(ENV_FILE); \
echo "# Kubernetes settings" >> $(ENV_FILE); \
echo "KUBE_CONTEXT=$(KUBE_CONTEXT)" >> $(ENV_FILE); \
echo "ISTIO_VERSION=$(ISTIO_VERSION)" >> $(ENV_FILE); \
echo "KIND_VERSION=$(KIND_VERSION)" >> $(ENV_FILE); \
echo "" >> $(ENV_FILE); \
echo "# Paths" >> $(ENV_FILE); \
echo "ROLES_DIR=$(ROLES_DIR)" >> $(ENV_FILE); \
echo "VAULT_PASSWORD_FILE=$(VAULT_PASSWORD_FILE)" >> $(ENV_FILE); \
echo "$(GREEN)✅ .env файл создан$(RESET)"; \
else \
echo "$(YELLOW)⚠️ .env файл уже существует$(RESET)"; \
fi
.PHONY: setup-vault
setup-vault: ## Создать vault-password.txt
@if [ ! -f $(VAULT_PASSWORD_FILE) ]; then \
echo "$(YELLOW)Создание vault-password.txt...$(RESET)"; \
echo "ansible-vault-password" > $(VAULT_PASSWORD_FILE); \
echo "$(GREEN)✅ vault-password.txt создан$(RESET)"; \
else \
echo "$(YELLOW)⚠️ vault-password.txt уже существует$(RESET)"; \
fi
.PHONY: setup-roles
setup-roles: ## Создать директорию для ролей
@mkdir -p $(ROLES_DIR)
@echo "$(GREEN)✅ Директория ролей создана: $(ROLES_DIR)$(RESET)"
.PHONY: setup-precommit
setup-precommit: ## Установить pre-commit хуки
@if command -v pre-commit >/dev/null 2>&1; then \
pre-commit install; \
echo "$(GREEN)✅ Pre-commit хуки установлены$(RESET)"; \
else \
echo "$(YELLOW)⚠️ pre-commit не установлен. Установите: pip install pre-commit$(RESET)"; \
fi
# =============================================================================
# УПРАВЛЕНИЕ ЛАБОРАТОРИЕЙ
# =============================================================================
.PHONY: lab
lab: ## Управление лабораторией (up|down|sh|test|create|converge|verify|destroy|reset)
@case "$(word 2, $(MAKECMDGOALS))" in \
up) \
echo "$(GREEN)🚀 Поднимаем контроллер...$(RESET)"; \
$(DOCKER_COMPOSE) up -d; \
echo "$(GREEN)✅ Контроллер запущен$(RESET)";; \
down) \
echo "$(YELLOW)🛑 Останавливаем контроллер...$(RESET)"; \
$(DOCKER_COMPOSE) down -v; \
echo "$(GREEN)✅ Контроллер остановлен$(RESET)";; \
sh) \
echo "$(BLUE)🐚 Входим в контроллер...$(RESET)"; \
docker exec -it ansible-controller bash;; \
test) \
echo "$(PURPLE)🧪 Запускаем полный цикл тестирования...$(RESET)"; \
$(MAKE) lab up; \
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=$(MOLECULE_EPHEMERAL_DIRECTORY) ansible-controller \
bash -lc 'cd /ansible && molecule test -s $(SCENARIO)'; \
echo "$(GREEN)✅ Тестирование завершено$(RESET)";; \
create) \
echo "$(BLUE)🏗️ Создаем инфраструктуру...$(RESET)"; \
$(MAKE) lab up; \
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=$(MOLECULE_EPHEMERAL_DIRECTORY) ansible-controller \
bash -lc 'cd /ansible && molecule create -s $(SCENARIO)'; \
echo "$(GREEN)✅ Инфраструктура создана$(RESET)";; \
converge) \
echo "$(YELLOW)⚙️ Запускаем роли...$(RESET)"; \
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=$(MOLECULE_EPHEMERAL_DIRECTORY) ansible-controller \
bash -lc 'cd /ansible && molecule converge -s $(SCENARIO)'; \
echo "$(GREEN)✅ Роли выполнены$(RESET)";; \
verify) \
echo "$(CYAN)🔍 Проверяем работу лаборатории...$(RESET)"; \
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=$(MOLECULE_EPHEMERAL_DIRECTORY) ansible-controller \
bash -lc 'cd /ansible && molecule verify -s $(SCENARIO)'; \
echo "$(GREEN)✅ Проверка завершена$(RESET)";; \
destroy) \
echo "$(RED)💥 Уничтожаем инфраструктуру...$(RESET)"; \
docker exec -e MOLECULE_EPHEMERAL_DIRECTORY=$(MOLECULE_EPHEMERAL_DIRECTORY) ansible-controller \
bash -lc 'cd /ansible && molecule destroy -s $(SCENARIO)'; \
echo "$(GREEN)✅ Инфраструктура уничтожена$(RESET)";; \
reset) \
echo "$(PURPLE)🔄 Полный сброс лаборатории...$(RESET)"; \
$(MAKE) lab destroy; \
$(MAKE) lab down; \
$(MAKE) lab up; \
echo "$(GREEN)✅ Лаборатория сброшена$(RESET)";; \
*) \
echo "Неизвестная команда. Доступные: up, down, sh, test, create, converge, verify, destroy, reset";; \
esac
# =============================================================================
# УПРАВЛЕНИЕ KUBERNETES
# =============================================================================
.PHONY: kube
kube: ## Управление Kubernetes (sh|cmd|enter|kiali|istio|grafana|prom|pf-stop|kubeconfig)
@case "$(word 2, $(MAKECMDGOALS))" in \
sh) \
echo "$(BLUE)🐚 Входим в контейнер с kubectl...$(RESET)"; \
docker exec -it ansible-controller bash;; \
cmd) \
if [ -z "$(CLUSTER)" ]; then \
echo "$(RED)❌ Использование: make kube cmd CLUSTER=lab CMD=\"get pods -A\"$(RESET)"; \
exit 1; \
fi; \
echo "$(CYAN)🔧 Выполняем kubectl команду...$(RESET)"; \
docker exec -it ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) $(CMD)';; \
enter) \
if [ -z "$(CLUSTER)" ]; then \
echo "$(RED)❌ Использование: make kube enter CLUSTER=lab$(RESET)"; \
exit 1; \
fi; \
echo "$(BLUE)🚪 Входим в кластер...$(RESET)"; \
docker exec -it ansible-controller bash -lc '\
POD=$$(kubectl --context kind-$(CLUSTER) -n lab-demo get pod -l app=toolbox -o jsonpath="{.items[0].metadata.name}"); \
[ -n "$$POD" ] || { echo "toolbox pod not found"; exit 1; }; \
kubectl --context kind-$(CLUSTER) -n lab-demo exec -it $$POD -- /bin/sh';; \
kiali) \
if [ -z "$(CLUSTER)" ]; then \
echo "$(RED)❌ Использование: make kube kiali CLUSTER=lab$(RESET)"; \
exit 1; \
fi; \
echo "$(PURPLE)🔮 Port-forward Kiali...$(RESET)"; \
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n istio-system port-forward svc/kiali 20001:20001'; \
echo "$(GREEN)✅ Kiali: http://localhost:20001$(RESET)";; \
istio) \
if [ -z "$(CLUSTER)" ]; then \
echo "$(RED)❌ Использование: make kube istio CLUSTER=lab$(RESET)"; \
exit 1; \
fi; \
echo "$(PURPLE)🌐 Port-forward Istio Gateway...$(RESET)"; \
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n istio-system port-forward svc/istio-ingressgateway 8082:80 8444:443'; \
echo "$(GREEN)✅ Istio GW: http://localhost:8082 https://localhost:8444$(RESET)";; \
grafana) \
if [ -z "$(CLUSTER)" ]; then \
echo "$(RED)❌ Использование: make kube grafana CLUSTER=lab$(RESET)"; \
exit 1; \
fi; \
echo "$(BLUE)📊 Port-forward Grafana...$(RESET)"; \
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n monitoring port-forward svc/monitoring-grafana 3000:80'; \
echo "$(GREEN)✅ Grafana: http://localhost:3000 (admin/admin)$(RESET)";; \
prom) \
if [ -z "$(CLUSTER)" ]; then \
echo "$(RED)❌ Использование: make kube prom CLUSTER=lab$(RESET)"; \
exit 1; \
fi; \
echo "$(YELLOW)📈 Port-forward Prometheus...$(RESET)"; \
docker exec -d ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) -n monitoring port-forward svc/monitoring-kube-prometheus-prometheus 9090:9090'; \
echo "$(GREEN)✅ Prometheus: http://localhost:9090$(RESET)";; \
pf-stop) \
echo "$(RED)🛑 Останавливаем все port-forward...$(RESET)"; \
docker exec -it ansible-controller bash -lc 'pkill -f "kubectl .* port-forward" || true'; \
echo "$(GREEN)✅ Port-forward остановлены$(RESET)";; \
kubeconfig) \
if [ -z "$(CLUSTER)" ]; then \
echo "$(RED)❌ Использование: make kube kubeconfig CLUSTER=lab$(RESET)"; \
exit 1; \
fi; \
echo "Получаем kubeconfig для кластера $(CLUSTER)..."; \
mkdir -p reports/kubeconfigs; \
docker exec ansible-controller bash -lc 'kubectl --context kind-$(CLUSTER) config view --raw' > reports/kubeconfigs/kubeconfig-$(CLUSTER).yaml; \
echo "Kubeconfig сохранен: reports/kubeconfigs/kubeconfig-$(CLUSTER).yaml";; \
*) \
echo "Неизвестная команда. Доступные: sh, cmd, enter, kiali, istio, grafana, prom, pf-stop, kubeconfig";; \
esac
# =============================================================================
# УПРАВЛЕНИЕ ПРЕСЕТАМИ
# =============================================================================
.PHONY: preset-create-interactive
preset-create-interactive: check-whiptail ## Интерактивное создание пресета
@echo "$(CYAN)🎯 Создание нового пресета лаборатории$(RESET)"; \
PRESET_NAME=$$(whiptail --inputbox "Введите имя пресета (например: my-lab):" 8 50 "my-lab" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
PRESET_DESC=$$(whiptail --inputbox "Введите описание пресета:" 8 50 "Мой лабораторный пресет" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
HOST_COUNT=$$(whiptail --inputbox "Количество хостов:" 8 50 "3" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
OS_FAMILY=$$(whiptail --menu "Выберите семейство ОС:" 15 50 4 "debian" "Debian/Ubuntu" "redhat" "RHEL/CentOS" "mixed" "Смешанное" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
FEATURES=$$(whiptail --checklist "Выберите функции:" 15 50 6 "docker" "Docker" off "dind" "Docker-in-Docker" off "k8s" "Kubernetes" off "istio" "Istio" off "monitoring" "Мониторинг" off "chaos" "Chaos Engineering" off 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
echo "$(BLUE)📝 Создание пресета: $$PRESET_NAME$(RESET)"; \
mkdir -p molecule/presets; \
echo "---" > molecule/presets/$$PRESET_NAME.yml; \
echo "# Пресет: $$PRESET_DESC" >> molecule/presets/$$PRESET_NAME.yml; \
echo "# Автор: $(AUTHOR)" >> molecule/presets/$$PRESET_NAME.yml; \
echo "# Сайт: $(SITE)" >> molecule/presets/$$PRESET_NAME.yml; \
echo "" >> molecule/presets/$$PRESET_NAME.yml; \
echo "hosts:" >> molecule/presets/$$PRESET_NAME.yml; \
for i in $$(seq 1 $$HOST_COUNT); do \
echo " - name: host$$i" >> molecule/presets/$$PRESET_NAME.yml; \
if [ "$$OS_FAMILY" = "debian" ]; then \
echo " family: debian" >> molecule/presets/$$PRESET_NAME.yml; \
elif [ "$$OS_FAMILY" = "redhat" ]; then \
echo " family: redhat" >> molecule/presets/$$PRESET_NAME.yml; \
else \
if [ $$((i % 2)) -eq 0 ]; then \
echo " family: debian" >> molecule/presets/$$PRESET_NAME.yml; \
else \
echo " family: redhat" >> molecule/presets/$$PRESET_NAME.yml; \
fi; \
fi; \
echo " groups: [all]" >> molecule/presets/$$PRESET_NAME.yml; \
done; \
echo "" >> molecule/presets/$$PRESET_NAME.yml; \
echo "features:" >> molecule/presets/$$PRESET_NAME.yml; \
echo " docker: $$(echo $$FEATURES | grep -q docker && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo " dind: $$(echo $$FEATURES | grep -q dind && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo " k8s: $$(echo $$FEATURES | grep -q k8s && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo " istio: $$(echo $$FEATURES | grep -q istio && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo " monitoring: $$(echo $$FEATURES | grep -q monitoring && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo " chaos: $$(echo $$FEATURES | grep -q chaos && echo 'true' || echo 'false')" >> molecule/presets/$$PRESET_NAME.yml; \
echo "$(GREEN)✅ Пресет $$PRESET_NAME создан: molecule/presets/$$PRESET_NAME.yml$(RESET)"; \
echo "$(BLUE)📋 Использование: make lab up PRESET=$$PRESET_NAME$(RESET)"
.PHONY: preset
preset: ## Управление пресетами (list|create|edit|test|copy|delete)
@case "$(word 2, $(MAKECMDGOALS))" in \
list) \
echo "Доступные пресеты:"; \
echo ""; \
echo "Классические пресеты:"; \
echo " minimal.yml - Минимальная лаборатория (1-3 машины)"; \
echo " webapp.yml - Веб-приложение (3-5 машин)"; \
echo " microservices.yml - Микросервисы (5-8 машин)"; \
echo " ha.yml - Высокая доступность (6-10 машин)"; \
echo " k8s-cluster.yml - Kubernetes кластер (8-12 машин)"; \
echo " cicd.yml - CI/CD пайплайн (10-15 машин)"; \
echo " bigdata.yml - Big Data кластер (12-18 машин)"; \
echo " servicemesh.yml - Service Mesh (15-20 машин)"; \
echo " enterprise.yml - Enterprise (18-20 машин)"; \
echo " maximum.yml - Максимальный (20 машин)"; \
echo ""; \
echo "Kubernetes пресеты:"; \
echo " k8s-single.yml - Kubernetes Single Node"; \
echo " k8s-multi.yml - Kubernetes Multi-Cluster"; \
echo " k8s-istio-full.yml - Kubernetes + Istio Full Stack"; \
echo ""; \
echo "DinD пресеты:"; \
echo " dind-simple.yml - DinD Simple"; \
echo " dind-swarm.yml - DinD Swarm"; \
echo " dind-compose.yml - DinD Compose"; \
echo ""; \
echo "DOoD пресеты:"; \
echo " dood-simple.yml - DOoD Simple"; \
echo " dood-mixed.yml - DOoD Mixed"; \
echo ""; \
echo "Смешанные пресеты:"; \
echo " mixed-k8s-dind.yml - Mixed Kubernetes + DinD"; \
echo " mixed-k8s-dood.yml - Mixed Kubernetes + DOoD"; \
echo " mixed-full.yml - Mixed Full Stack";; \
create) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make preset create NAME=my-preset$(RESET)"; \
exit 1; \
fi; \
echo "$(YELLOW)📝 Создаем пресет: $(NAME).yml$(RESET)"; \
$(MAKE) preset copy SOURCE=minimal.yml TARGET=$(NAME).yml; \
echo "$(GREEN)✅ Пресет создан: molecule/presets/$(NAME).yml$(RESET)";; \
edit) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make preset edit NAME=my-preset$(RESET)"; \
exit 1; \
fi; \
echo "$(BLUE)✏️ Редактируем пресет: $(NAME).yml$(RESET)"; \
$${EDITOR:-vim} molecule/presets/$(NAME).yml;; \
test) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make preset test NAME=my-preset$(RESET)"; \
exit 1; \
fi; \
echo "$(PURPLE)🧪 Тестируем пресет: $(NAME).yml$(RESET)"; \
$(MAKE) lab test LAB_SPEC=molecule/presets/$(NAME).yml;; \
copy) \
if [ -z "$(SOURCE)" ] || [ -z "$(TARGET)" ]; then \
echo "$(RED)❌ Использование: make preset copy SOURCE=minimal.yml TARGET=my-preset.yml$(RESET)"; \
exit 1; \
fi; \
echo "$(YELLOW)📋 Копируем пресет: $(SOURCE) -> $(TARGET)$(RESET)"; \
cp molecule/presets/$(SOURCE) molecule/presets/$(TARGET); \
echo "$(GREEN)✅ Пресет скопирован$(RESET)";; \
delete) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make preset delete NAME=my-preset$(RESET)"; \
exit 1; \
fi; \
if [ -f "molecule/presets/$(NAME).yml" ]; then \
echo "$(RED)🗑️ Удаляем пресет: $(NAME)$(RESET)"; \
rm -f "molecule/presets/$(NAME).yml"; \
echo "$(GREEN)✅ Пресет $(NAME) удален$(RESET)"; \
else \
echo "$(RED)❌ Пресет $(NAME) не найден$(RESET)"; \
exit 1; \
fi;; \
*) \
echo "Неизвестная команда. Доступные: list, create, edit, test, copy, delete";; \
esac
# =============================================================================
# УПРАВЛЕНИЕ РОЛЯМИ
# =============================================================================
.PHONY: playbook-create-interactive
playbook-create-interactive: check-whiptail ## Интерактивное создание playbook
@echo "$(CYAN)🎯 Создание нового Ansible playbook$(RESET)"; \
PLAYBOOK_NAME=$$(whiptail --inputbox "Введите имя playbook (например: deploy.yml):" 8 50 "deploy.yml" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
PLAYBOOK_DESC=$$(whiptail --inputbox "Введите описание playbook:" 8 50 "Развертывание приложения" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
PLAYBOOK_HOSTS=$$(whiptail --inputbox "Целевые хосты (по умолчанию: all):" 8 50 "all" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
PLAYBOOK_ROLES=$$(whiptail --inputbox "Роли через запятую (например: nginx,apache):" 8 50 "nginx" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
PLAYBOOK_TAGS=$$(whiptail --inputbox "Теги через запятую (например: deploy,web):" 8 50 "deploy" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
echo "$(BLUE)📝 Создание playbook: $$PLAYBOOK_NAME$(RESET)"; \
mkdir -p files/playbooks; \
echo "---" > files/playbooks/$$PLAYBOOK_NAME; \
echo "# Playbook: $$PLAYBOOK_DESC" >> files/playbooks/$$PLAYBOOK_NAME; \
echo "# Автор: $(AUTHOR)" >> files/playbooks/$$PLAYBOOK_NAME; \
echo "# Сайт: $(SITE)" >> files/playbooks/$$PLAYBOOK_NAME; \
echo "" >> files/playbooks/$$PLAYBOOK_NAME; \
echo "- name: $$PLAYBOOK_DESC" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " hosts: $$PLAYBOOK_HOSTS" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " gather_facts: true" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " tags: [$$PLAYBOOK_TAGS]" >> files/playbooks/$$PLAYBOOK_NAME; \
echo "" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " pre_tasks:" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " - name: Update system packages" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " package:" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " name: '*'"; \
echo " state: latest" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " when: ansible_os_family in ['Debian', 'RedHat']" >> files/playbooks/$$PLAYBOOK_NAME; \
echo "" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " roles:" >> files/playbooks/$$PLAYBOOK_NAME; \
for role in $$(echo $$PLAYBOOK_ROLES | tr ',' ' '); do \
echo " - role: $$role" >> files/playbooks/$$PLAYBOOK_NAME; \
done; \
echo "" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " post_tasks:" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " - name: Verify deployment" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " debug:" >> files/playbooks/$$PLAYBOOK_NAME; \
echo " msg: \"Playbook $$PLAYBOOK_NAME completed successfully\"" >> files/playbooks/$$PLAYBOOK_NAME; \
echo "$(GREEN)✅ Playbook $$PLAYBOOK_NAME создан$(RESET)"; \
echo "$(BLUE)📁 Файл: files/playbooks/$$PLAYBOOK_NAME$(RESET)"; \
echo "$(BLUE)📋 Запуск: ansible-playbook files/playbooks/$$PLAYBOOK_NAME$(RESET)"
.PHONY: role-create-interactive
role-create-interactive: check-whiptail ## Интерактивное создание роли
@echo "$(CYAN)🎯 Создание новой Ansible роли$(RESET)"; \
ROLE_NAME=$$(whiptail --inputbox "Введите имя роли (например: nginx):" 8 50 "nginx" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
ROLE_DESC=$$(whiptail --inputbox "Введите описание роли:" 8 50 "Установка и настройка nginx" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
ROLE_PACKAGE=$$(whiptail --inputbox "Основной пакет (по умолчанию: $$ROLE_NAME):" 8 50 "$$ROLE_NAME" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
ROLE_SERVICE=$$(whiptail --inputbox "Имя сервиса (по умолчанию: $$ROLE_NAME):" 8 50 "$$ROLE_NAME" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
ROLE_PLATFORMS=$$(whiptail --checklist "Поддерживаемые платформы:" 15 50 4 "ubuntu" "Ubuntu" on "centos" "CentOS" on "rhel" "RHEL" off "debian" "Debian" off 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
ROLE_TAGS=$$(whiptail --inputbox "Теги через запятую (по умолчанию: $$ROLE_NAME):" 8 50 "$$ROLE_NAME,web,server" 3>&1 1>&2 2>&3); \
if [ $$? -ne 0 ]; then echo "$(RED)❌ Отменено$(RESET)"; exit 1; fi; \
echo "$(BLUE)📝 Создание роли: $$ROLE_NAME$(RESET)"; \
mkdir -p $(ROLES_DIR)/$${ROLE_NAME}/{tasks,handlers,templates,files,vars,defaults,meta,tests,playbooks}; \
echo "$(BLUE)📝 Создаем основные файлы...$(RESET)"; \
echo "---" > $(ROLES_DIR)/$${ROLE_NAME}/tasks/main.yml; \
echo "# Основные задачи роли $${ROLE_NAME}" >> $(ROLES_DIR)/$${ROLE_NAME}/tasks/main.yml; \
echo "# Автор: $(AUTHOR)" >> $(ROLES_DIR)/$${ROLE_NAME}/tasks/main.yml; \
echo "# Сайт: $(SITE)" >> $(ROLES_DIR)/$${ROLE_NAME}/tasks/main.yml; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo "- name: $$ROLE_NAME placeholder" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo " debug:" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo " msg: \"Роль $$ROLE_NAME готова для настройки\"" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo "- name: Include OS-specific tasks" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo " include_tasks: \"{{ ansible_os_family | lower }}.yml\"" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo "- name: Start $$ROLE_NAME service" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo " systemd:" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo " name: \"{{ $${ROLE_NAME}_service | default('$$ROLE_SERVICE') }}\"" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo " state: started" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo " enabled: true" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo " when: $${ROLE_NAME}_service is defined" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml; \
echo "---" > $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo "# Задачи для Debian/Ubuntu семейства" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo "# Автор: $(AUTHOR)" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo "# Сайт: $(SITE)" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo "- name: Update apt cache (Debian)" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo " apt:" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo " update_cache: true" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo " cache_valid_time: 3600" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo " when: ansible_os_family == 'Debian'" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo "- name: Install $$ROLE_NAME package (Debian)" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo " apt:" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo " name: \"{{ $${ROLE_NAME}_package | default('$$ROLE_PACKAGE') }}\"" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo " state: present" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo " when: ansible_os_family == 'Debian'" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/debian.yml; \
echo "---" > $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo "# Задачи для RHEL/CentOS семейства" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo "# Автор: $(AUTHOR)" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo "# Сайт: $(SITE)" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo "- name: Update yum cache (RHEL)" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo " yum:" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo " update_cache: true" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo " when: ansible_os_family == 'RedHat'" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo "- name: Install $$ROLE_NAME package (RHEL)" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo " yum:" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo " name: \"{{ $${ROLE_NAME}_package | default('$$ROLE_PACKAGE') }}\"" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo " state: present" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo " when: ansible_os_family == 'RedHat'" >> $(ROLES_DIR)/$$ROLE_NAME/tasks/redhat.yml; \
echo "---" > $(ROLES_DIR)/$$ROLE_NAME/defaults/main.yml; \
echo "# Переменные по умолчанию для роли $$ROLE_NAME" >> $(ROLES_DIR)/$$ROLE_NAME/defaults/main.yml; \
echo "# Автор: $(AUTHOR)" >> $(ROLES_DIR)/$$ROLE_NAME/defaults/main.yml; \
echo "# Сайт: $(SITE)" >> $(ROLES_DIR)/$$ROLE_NAME/defaults/main.yml; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/defaults/main.yml; \
echo "$${ROLE_NAME}_enabled: true" >> $(ROLES_DIR)/$$ROLE_NAME/defaults/main.yml; \
echo "$${ROLE_NAME}_package: $$ROLE_PACKAGE" >> $(ROLES_DIR)/$$ROLE_NAME/defaults/main.yml; \
echo "$${ROLE_NAME}_service: $$ROLE_SERVICE" >> $(ROLES_DIR)/$$ROLE_NAME/defaults/main.yml; \
echo "---" > $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo "galaxy_info:" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " author: $(AUTHOR)" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " description: $$ROLE_DESC" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " company: $(SITE)" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " license: MIT" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " min_ansible_version: 2.9" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " platforms:" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " - name: Ubuntu" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " versions: [focal, jammy]" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " - name: CentOS" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " versions: [7, 8, 9]" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " - name: RHEL" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " versions: [7, 8, 9]" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo " galaxy_tags: [$${ROLE_TAGS}]" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo "dependencies: []" >> $(ROLES_DIR)/$$ROLE_NAME/meta/main.yml; \
echo "---" > $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "# Роль $$ROLE_NAME" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "$$ROLE_DESC" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "## Переменные" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "| Переменная | По умолчанию | Описание |" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "|------------|--------------|----------|" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "| \`$${ROLE_NAME}_enabled\` | \`true\` | Включить роль |" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "| \`$${ROLE_NAME}_package\` | \`$$ROLE_PACKAGE\` | Имя пакета |" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "| \`$${ROLE_NAME}_service\` | \`$$ROLE_SERVICE\` | Имя сервиса |" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "## Использование" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "\`\`\`yaml" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "- hosts: all" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo " roles:" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo " - role: $$ROLE_NAME" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "\`\`\`" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "## Автор" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "$(AUTHOR)" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "Сайт: $(SITE)" >> $(ROLES_DIR)/$$ROLE_NAME/README.md; \
echo "$(GREEN)✅ Роль $$ROLE_NAME создана$(RESET)"; \
echo "$(BLUE)📁 Структура: $(ROLES_DIR)/$$ROLE_NAME/$(RESET)"; \
echo "$(BLUE)📝 Основной файл: $(ROLES_DIR)/$$ROLE_NAME/tasks/main.yml$(RESET)"; \
echo "$(BLUE)📋 Playbooks: $(ROLES_DIR)/$$ROLE_NAME/playbooks/$(RESET)"
.PHONY: role
role: ## Управление ролями (list|create|edit|test|lint|deploy|delete)
@case "$(word 2, $(MAKECMDGOALS))" in \
list) \
echo "Доступные роли:"; \
if [ -d "$(ROLES_DIR)" ]; then \
ls -la $(ROLES_DIR)/ | grep "^d" | awk '{print " " $$9}' | grep -v "^\\.$$"; \
else \
echo " Директория ролей не найдена"; \
fi;; \
create) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make role create NAME=my-role$(RESET)"; \
exit 1; \
fi; \
echo "$(YELLOW)📝 Создаем роль: $(NAME)$(RESET)"; \
echo "$(BLUE)🔧 Настройка роли...$(RESET)"; \
read -p "$(YELLOW)📝 Описание роли: $(RESET)" ROLE_DESC; \
read -p "$(YELLOW)📦 Основной пакет (по умолчанию: $(NAME)): $(RESET)" ROLE_PACKAGE; \
ROLE_PACKAGE=$${ROLE_PACKAGE:-$(NAME)}; \
read -p "$(YELLOW)🔧 Сервис (по умолчанию: $(NAME)): $(RESET)" ROLE_SERVICE; \
ROLE_SERVICE=$${ROLE_SERVICE:-$(NAME)}; \
read -p "$(YELLOW)📋 Платформы (ubuntu,centos,rhel) через запятую: $(RESET)" ROLE_PLATFORMS; \
ROLE_PLATFORMS=$${ROLE_PLATFORMS:-ubuntu,centos}; \
read -p "$(YELLOW)🏷️ Теги через запятую: $(RESET)" ROLE_TAGS; \
ROLE_TAGS=$${ROLE_TAGS:-$(NAME)}; \
echo "$(BLUE)📁 Создаем структуру роли...$(RESET)"; \
mkdir -p $(ROLES_DIR)/$(NAME)/{tasks,handlers,templates,files,vars,defaults,meta,tests,playbooks}; \
echo "$(BLUE)📝 Создаем основные файлы...$(RESET)"; \
echo "---" > $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo "# Основные задачи роли $(NAME)" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo "# Автор: $(AUTHOR)" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo "# Сайт: $(SITE)" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo "- name: $(NAME) placeholder" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo " debug:" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo " msg: \"Роль $(NAME) готова для настройки\"" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo "- name: Include OS-specific tasks" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo " include_tasks: \"{{ ansible_os_family | lower }}.yml\"" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo "- name: Start $(NAME) service" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo " systemd:" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo " name: \"{{ $(NAME)_service | default('$(ROLE_SERVICE)') }}\"" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo " state: started" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo " enabled: true" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo " when: $(NAME)_service is defined" >> $(ROLES_DIR)/$(NAME)/tasks/main.yml; \
echo "---" > $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo "# Задачи для Debian/Ubuntu семейства" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo "# Автор: $(AUTHOR)" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo "# Сайт: $(SITE)" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo "- name: Update apt cache (Debian)" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo " apt:" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo " update_cache: true" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo " cache_valid_time: 3600" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo " when: ansible_os_family == 'Debian'" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo "- name: Install $(NAME) package (Debian)" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo " apt:" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo " name: \"{{ $(NAME)_package | default('$(ROLE_PACKAGE)') }}\"" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo " state: present" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo " when: ansible_os_family == 'Debian'" >> $(ROLES_DIR)/$(NAME)/tasks/debian.yml; \
echo "---" > $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo "# Задачи для RHEL/CentOS семейства" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo "# Автор: $(AUTHOR)" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo "# Сайт: $(SITE)" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo "- name: Update yum cache (RHEL)" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo " yum:" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo " update_cache: true" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo " when: ansible_os_family == 'RedHat'" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo "- name: Install $(NAME) package (RHEL)" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo " yum:" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo " name: \"{{ $(NAME)_package | default('$(ROLE_PACKAGE)') }}\"" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo " state: present" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo " when: ansible_os_family == 'RedHat'" >> $(ROLES_DIR)/$(NAME)/tasks/redhat.yml; \
echo "---" > $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
echo "# Переменные по умолчанию для роли $(NAME)" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
echo "# Автор: $(AUTHOR)" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
echo "# Сайт: $(SITE)" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
echo "$(NAME)_enabled: true" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
echo "$(NAME)_package: $(ROLE_PACKAGE)" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
echo "$(NAME)_service: $(ROLE_SERVICE)" >> $(ROLES_DIR)/$(NAME)/defaults/main.yml; \
echo "---" > $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo "galaxy_info:" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " author: $(AUTHOR)" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " description: $(ROLE_DESC)" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " company: $(SITE)" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " license: MIT" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " min_ansible_version: 2.9" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " platforms:" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " - name: Ubuntu" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " versions: [focal, jammy]" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " - name: CentOS" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " versions: [7, 8, 9]" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " - name: RHEL" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " versions: [7, 8, 9]" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo " galaxy_tags: [$(ROLE_TAGS)]" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo "dependencies: []" >> $(ROLES_DIR)/$(NAME)/meta/main.yml; \
echo "---" > $(ROLES_DIR)/$(NAME)/README.md; \
echo "# Роль $(NAME)" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "$(ROLE_DESC)" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "## Переменные" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "| Переменная | По умолчанию | Описание |" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "|------------|--------------|----------|" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "| \`$(NAME)_enabled\` | \`true\` | Включить роль |" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "| \`$(NAME)_package\` | \`$(ROLE_PACKAGE)\` | Имя пакета |" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "| \`$(NAME)_service\` | \`$(ROLE_SERVICE)\` | Имя сервиса |" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "## Использование" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "\`\`\`yaml" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "- hosts: all" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo " roles:" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo " - role: $(NAME)" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "\`\`\`" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "## Автор" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "$(AUTHOR)" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "Сайт: $(SITE)" >> $(ROLES_DIR)/$(NAME)/README.md; \
echo "$(GREEN)✅ Роль $(NAME) создана$(RESET)"; \
echo "$(BLUE)📁 Структура: $(ROLES_DIR)/$(NAME)/$(RESET)"; \
echo "$(BLUE)📝 Основной файл: $(ROLES_DIR)/$(NAME)/tasks/main.yml$(RESET)"; \
echo "$(BLUE)📋 Playbooks: $(ROLES_DIR)/$(NAME)/playbooks/$(RESET)";; \
edit) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make role edit NAME=my-role$(RESET)"; \
exit 1; \
fi; \
echo "$(BLUE)✏️ Редактируем роль: $(NAME)$(RESET)"; \
$${EDITOR:-vim} $(ROLES_DIR)/$(NAME)/tasks/main.yml;; \
test) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make role test NAME=my-role$(RESET)"; \
exit 1; \
fi; \
echo "$(PURPLE)🧪 Тестируем роль: $(NAME)$(RESET)"; \
$(MAKE) lab test LAB_SPEC=molecule/presets/minimal.yml;; \
lint) \
echo "$(YELLOW)🔍 Проверяем роли...$(RESET)"; \
docker exec ansible-controller bash -lc 'ansible-lint --config-file /ansible/.ansible-lint $(ROLES_DIR)/*'; \
echo "$(GREEN)✅ Проверка завершена$(RESET)";; \
deploy) \
echo "$(PURPLE)🚀 Развертываем роли...$(RESET)"; \
docker exec ansible-controller bash -lc 'ansible-playbook -i /tmp/molecule/inventory/hosts.yml files/playbooks/site.yml'; \
echo "$(GREEN)✅ Развертывание завершено$(RESET)";; \
info) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make role info NAME=my-role$(RESET)"; \
exit 1; \
fi; \
echo "$(BLUE)📋 Информация о роли: $(NAME)$(RESET)"; \
docker exec ansible-controller bash -lc 'cat /ansible/roles/$(NAME)/README.md';; \
playbook) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make role playbook NAME=my-role$(RESET)"; \
exit 1; \
fi; \
echo "$(BLUE)📋 Управление playbooks для роли: $(NAME)$(RESET)"; \
echo "$(YELLOW)Доступные команды:$(RESET)"; \
echo " $(CYAN)create$(RESET) - Создать новый playbook"; \
echo " $(CYAN)list$(RESET) - Список playbooks"; \
echo " $(CYAN)edit$(RESET) - Редактировать playbook"; \
echo " $(CYAN)run$(RESET) - Запустить playbook"; \
read -p "$(YELLOW)Выберите команду: $(RESET)" PLAYBOOK_CMD; \
case "$$PLAYBOOK_CMD" in \
create) \
read -p "$(YELLOW)📝 Имя playbook: $(RESET)" PLAYBOOK_NAME; \
if [ -z "$$PLAYBOOK_NAME" ]; then \
echo "$(RED)❌ Имя playbook обязательно$(RESET)"; \
exit 1; \
fi; \
echo "---" > $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo "# Playbook: $$PLAYBOOK_NAME для роли $(NAME)" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo "# Автор: $(AUTHOR)" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo "# Сайт: $(SITE)" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo "- name: $$PLAYBOOK_NAME" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " hosts: all" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " become: true" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " gather_facts: true" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " vars:" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " # Переменные для роли $(NAME)" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " $(NAME)_enabled: true" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " pre_tasks:" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " - name: Display OS information" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " debug:" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " msg: \"OS Family: {{ ansible_os_family }}, OS: {{ ansible_distribution }} {{ ansible_distribution_version }}\"" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " roles:" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " - role: $(NAME)" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo "" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " post_tasks:" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " - name: Verify $(NAME) installation" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " debug:" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo " msg: \"$(NAME) successfully deployed on {{ inventory_hostname }}\"" >> $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
echo "$(GREEN)✅ Playbook $$PLAYBOOK_NAME создан$(RESET)";; \
list) \
echo "$(CYAN)📋 Playbooks для роли $(NAME):$(RESET)"; \
if [ -d "$(ROLES_DIR)/$(NAME)/playbooks" ]; then \
ls -la $(ROLES_DIR)/$(NAME)/playbooks/*.yml 2>/dev/null | awk '{print " " $$9}' || echo " $(YELLOW)Нет playbooks$(RESET)"; \
else \
echo " $(YELLOW)Директория playbooks не найдена$(RESET)"; \
fi;; \
edit) \
read -p "$(YELLOW)📝 Имя playbook для редактирования: $(RESET)" PLAYBOOK_NAME; \
if [ -f "$(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml" ]; then \
$${EDITOR:-vim} $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml; \
else \
echo "$(RED)❌ Playbook $$PLAYBOOK_NAME не найден$(RESET)"; \
fi;; \
run) \
read -p "$(YELLOW)📝 Имя playbook для запуска: $(RESET)" PLAYBOOK_NAME; \
if [ -f "$(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml" ]; then \
echo "$(BLUE)🚀 Запускаем playbook: $$PLAYBOOK_NAME$(RESET)"; \
docker exec ansible-controller bash -lc "ansible-playbook -i /tmp/molecule/inventory/hosts.yml $(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml"; \
else \
echo "$(RED)❌ Playbook $$PLAYBOOK_NAME не найден$(RESET)"; \
fi;; \
delete) \
read -p "$(YELLOW)📝 Имя playbook для удаления: $(RESET)" PLAYBOOK_NAME; \
if [ -f "$(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml" ]; then \
echo "$(RED)🗑️ Удаляем playbook: $$PLAYBOOK_NAME$(RESET)"; \
rm -f "$(ROLES_DIR)/$(NAME)/playbooks/$$PLAYBOOK_NAME.yml"; \
echo "$(GREEN)✅ Playbook $$PLAYBOOK_NAME удален$(RESET)"; \
else \
echo "$(RED)❌ Playbook $$PLAYBOOK_NAME не найден$(RESET)"; \
fi;; \
*) \
echo "Неизвестная команда playbook. Доступные: create, list, edit, run, delete";; \
esac;; \
delete) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make role delete NAME=my-role$(RESET)"; \
exit 1; \
fi; \
if [ -d "$(ROLES_DIR)/$(NAME)" ]; then \
echo "$(RED)🗑️ Удаляем роль: $(NAME)$(RESET)"; \
rm -rf "$(ROLES_DIR)/$(NAME)"; \
echo "$(GREEN)✅ Роль $(NAME) удалена$(RESET)"; \
else \
echo "$(RED)❌ Роль $(NAME) не найдена$(RESET)"; \
exit 1; \
fi;; \
*) \
echo "Неизвестная команда. Доступные: list, create, edit, test, lint, deploy, delete, info, playbook";; \
esac
# =============================================================================
# УПРАВЛЕНИЕ VAULT
# =============================================================================
.PHONY: vault
vault: ## Управление Ansible Vault (show|create|edit|delete|rekey|decrypt|encrypt)
@case "$(word 2, $(MAKECMDGOALS))" in \
show) \
echo "Показываем содержимое vault..."; \
docker exec ansible-controller bash -lc 'ansible-vault view --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
create) \
echo "$(YELLOW)📝 Создаем vault файл...$(RESET)"; \
docker exec ansible-controller bash -lc 'echo "---" > vault/secrets.yml && ansible-vault encrypt --encrypt-vault-id default --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
edit) \
echo "$(BLUE)✏️ Редактируем vault файл...$(RESET)"; \
docker exec ansible-controller bash -lc 'ansible-vault edit --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
delete) \
echo "$(RED)🗑️ Удаляем vault файл...$(RESET)"; \
docker exec ansible-controller bash -lc 'rm vault/secrets.yml';; \
rekey) \
echo "$(YELLOW)🔑 Изменяем пароль vault...$(RESET)"; \
docker exec ansible-controller bash -lc 'ansible-vault rekey --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
decrypt) \
echo "$(GREEN)🔓 Расшифровываем vault файл...$(RESET)"; \
docker exec ansible-controller bash -lc 'ansible-vault decrypt --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
encrypt) \
echo "$(RED)🔒 Шифруем vault файл...$(RESET)"; \
docker exec ansible-controller bash -lc 'ansible-vault encrypt --encrypt-vault-id default --vault-password-file $(VAULT_PASSWORD_FILE) vault/secrets.yml';; \
*) \
echo "Неизвестная команда. Доступные: show, create, edit, delete, rekey, decrypt, encrypt";; \
esac
# =============================================================================
# УПРАВЛЕНИЕ GIT
# =============================================================================
.PHONY: git
git: ## Управление Git (status|add|commit|push|pull|branch|merge)
@case "$(word 2, $(MAKECMDGOALS))" in \
status) \
echo "$(CYAN)📊 Статус Git репозитория:$(RESET)"; \
git status;; \
add) \
echo "$(GREEN) Добавляем файлы в Git...$(RESET)"; \
git add .;; \
commit) \
if [ -z "$(MESSAGE)" ]; then \
echo "$(RED)❌ Использование: make git commit MESSAGE=\"your commit message\"$(RESET)"; \
exit 1; \
fi; \
echo "$(YELLOW)💾 Создаем коммит...$(RESET)"; \
git commit -m "$(MESSAGE)";; \
push) \
echo "$(BLUE)🚀 Отправляем изменения...$(RESET)"; \
git push;; \
pull) \
echo "$(GREEN)📥 Получаем изменения...$(RESET)"; \
git pull;; \
branch) \
if [ -z "$(NAME)" ]; then \
echo "$(RED)❌ Использование: make git branch NAME=my-branch$(RESET)"; \
exit 1; \
fi; \
echo "$(PURPLE)🌿 Создаем ветку: $(NAME)$(RESET)"; \
git checkout -b $(NAME);; \
merge) \
if [ -z "$(BRANCH)" ]; then \
echo "$(RED)❌ Использование: make git merge BRANCH=my-branch$(RESET)"; \
exit 1; \
fi; \
echo "$(YELLOW)🔀 Сливаем ветку: $(BRANCH)$(RESET)"; \
git merge $(BRANCH);; \
*) \
echo "Неизвестная команда. Доступные: status, add, commit, push, pull, branch, merge";; \
esac
# =============================================================================
# УПРАВЛЕНИЕ DOCKER
# =============================================================================
.PHONY: docker
docker: ## Управление Docker (build|rebuild|prune|shell|logs|stop|start)
@case "$(word 2, $(MAKECMDGOALS))" in \
build) \
echo "$(YELLOW)🔨 Собираем Docker образы...$(RESET)"; \
$(DOCKER_COMPOSE) build;; \
rebuild) \
echo "$(YELLOW)🔨 Пересобираем Docker образы...$(RESET)"; \
$(DOCKER_COMPOSE) build --no-cache;; \
prune) \
echo "$(RED)🧹 Очищаем Docker...$(RESET)"; \
docker system prune -af;; \
shell) \
echo "$(BLUE)🐚 Входим в Docker контейнер...$(RESET)"; \
docker exec -it ansible-controller bash;; \
logs) \
echo "$(CYAN)📋 Показываем логи...$(RESET)"; \
$(DOCKER_COMPOSE) logs -f;; \
stop) \
echo "$(RED)🛑 Останавливаем контейнеры...$(RESET)"; \
$(DOCKER_COMPOSE) stop;; \
start) \
echo "$(GREEN)▶️ Запускаем контейнеры...$(RESET)"; \
$(DOCKER_COMPOSE) start;; \
*) \
echo "Неизвестная команда. Доступные: build, rebuild, prune, shell, logs, stop, start";; \
esac
# =============================================================================
# ОТЧЕТЫ И МОНИТОРИНГ
# =============================================================================
.PHONY: report
report: ## Сгенерировать HTML отчет
@echo "$(PURPLE)📊 Генерируем HTML отчет...$(RESET)"
@mkdir -p reports
@docker exec ansible-controller bash -lc 'python3 /ansible/scripts/report_html.py /ansible/reports/lab-health.json /ansible/reports/lab-report.html'
@echo "$(GREEN)✅ HTML отчет: reports/lab-report.html$(RESET)"
@echo "$(YELLOW)📖 Откройте отчет в браузере:$(RESET)"
@echo " $(BLUE)file://$(PWD)/reports/lab-report.html$(RESET)"
.PHONY: kubeconfigs
kubeconfigs: ## Получить все kubeconfig файлы
@echo "$(BLUE)📋 Получаем все kubeconfig файлы...$(RESET)"
@mkdir -p reports/kubeconfigs
@docker exec ansible-controller bash -lc 'for cluster in $$(kind get clusters 2>/dev/null || echo ""); do \
if [ -n "$$cluster" ]; then \
echo "Получаем kubeconfig для $$cluster..."; \
kubectl --context kind-$$cluster config view --raw > /ansible/reports/kubeconfigs/kubeconfig-$$cluster.yaml; \
fi; \
done'
@echo "$(GREEN)✅ Kubeconfig файлы сохранены в reports/kubeconfigs/$(RESET)"
@if [ -d "reports/kubeconfigs" ] && [ -n "$$(ls reports/kubeconfigs/ 2>/dev/null)" ]; then \
echo "$(YELLOW)📁 Найденные kubeconfig файлы:$(RESET)"; \
ls -la reports/kubeconfigs/ | grep -v "^total" | awk '{print " " $$9}'; \
fi
.PHONY: open-report
open-report: ## Открыть HTML отчет в браузере
@if [ -f "reports/lab-report.html" ]; then \
echo "$(BLUE)🌐 Открываем отчет в браузере...$(RESET)"; \
if command -v open >/dev/null 2>&1; then \
open reports/lab-report.html; \
elif command -v xdg-open >/dev/null 2>&1; then \
xdg-open reports/lab-report.html; \
else \
echo "$(YELLOW)⚠️ Откройте отчет вручную: file://$(PWD)/reports/lab-report.html$(RESET)"; \
fi; \
echo "$(GREEN)✅ Отчет открыт$(RESET)"; \
else \
echo "$(RED)❌ Отчет не найден. Сначала выполните: make report$(RESET)"; \
fi
.PHONY: full-test
full-test: ## Полный цикл тестирования с отчетом и kubeconfig
@echo "$(PURPLE)🚀 Запускаем полный цикл тестирования...$(RESET)"
@$(MAKE) lab test
@echo "$(BLUE)📊 Генерируем отчеты...$(RESET)"
@$(MAKE) report
@$(MAKE) kubeconfigs
@echo "$(GREEN)✅ Полный цикл завершен!$(RESET)"
@echo "$(YELLOW)📁 Результаты:$(RESET)"
@echo " $(BLUE)📊 HTML отчет: reports/lab-report.html$(RESET)"
@echo " $(BLUE)📋 Kubeconfig файлы: reports/kubeconfigs/$(RESET)"
@echo "$(YELLOW)🌐 Открыть отчет: make open-report$(RESET)"
.PHONY: chaos
chaos: ## Запустить Chaos Engineering тесты
@echo "$(RED)🧨 Запускаем Chaos Engineering...$(RESET)"
@docker exec ansible-controller bash -lc 'ansible-playbook -i /tmp/molecule/inventory/hosts.yml /ansible/files/playbooks/chaos.yml'
@echo "$(GREEN)✅ Chaos Engineering завершен$(RESET)"
.PHONY: check-secrets
check-secrets: ## Проверить безопасность секретов
@echo "$(YELLOW)🔍 Проверяем безопасность секретов...$(RESET)"
@docker exec ansible-controller bash -lc 'bash /ansible/scripts/secret_scan.sh'
@echo "$(GREEN)✅ Проверка секретов завершена$(RESET)"
.PHONY: idempotence
idempotence: ## Проверить идемпотентность
@echo "$(BLUE)🔄 Проверяем идемпотентность...$(RESET)"
@docker exec ansible-controller bash -lc 'ansible-playbook -i /tmp/molecule/inventory/hosts.yml /ansible/files/playbooks/site.yml --check'
@echo "$(GREEN)✅ Идемпотентность проверена$(RESET)"
.PHONY: snapshot
snapshot: ## Сохранить снапшот лаборатории
@echo "$(YELLOW)📸 Создаем снапшот...$(RESET)"
@docker exec ansible-controller bash -lc 'bash /ansible/scripts/snapshot.sh'
@echo "$(GREEN)✅ Снапшот сохранен$(RESET)"
.PHONY: restore
restore: ## Восстановить из снапшота
@echo "$(BLUE)🔄 Восстанавливаем из снапшота...$(RESET)"
@docker exec ansible-controller bash -lc 'bash /ansible/scripts/restore.sh'
@echo "$(GREEN)✅ Снапшот восстановлен$(RESET)"
.PHONY: cleanup
cleanup: ## Очистить лабораторию
@echo "$(RED)🧹 Очищаем лабораторию...$(RESET)"
@docker exec ansible-controller bash -lc 'bash /ansible/scripts/cleanup.sh'
@echo "$(GREEN)✅ Лаборатория очищена$(RESET)"
# =============================================================================
# УТИЛИТЫ
# =============================================================================
.PHONY: lint
lint: ## Проверить весь проект на ошибки
@echo "Проверяем весь проект..."
@docker exec ansible-controller bash -lc 'ansible-lint --config-file /ansible/.ansible-lint molecule/universal/'
@docker exec ansible-controller bash -lc 'ansible-lint --config-file /ansible/.ansible-lint files/playbooks/'
@if [ -d "$(ROLES_DIR)" ] && [ -n "$$(ls $(ROLES_DIR)/ 2>/dev/null)" ]; then \
docker exec ansible-controller bash -lc 'ansible-lint --config-file /ansible/.ansible-lint $(ROLES_DIR)/*'; \
fi
@echo "Проверка завершена"
.PHONY: env
env: ## Показать переменные окружения
@echo "$(CYAN)🔧 Переменные окружения:$(RESET)"
@echo "PROJECT_NAME: $(PROJECT_NAME)"
@echo "VERSION: $(VERSION)"
@echo "AUTHOR: $(AUTHOR)"
@echo "SITE: $(SITE)"
@echo "DOCKER_IMAGE: $(DOCKER_IMAGE)"
@echo "DOCKER_NETWORK: $(DOCKER_NETWORK)"
@echo "SCENARIO: $(SCENARIO)"
@echo "LAB_SPEC: $(LAB_SPEC)"
@echo "KUBE_CONTEXT: $(KUBE_CONTEXT)"
@echo "ROLES_DIR: $(ROLES_DIR)"
@echo "VAULT_PASSWORD_FILE: $(VAULT_PASSWORD_FILE)"
.PHONY: clean
clean: cleanup ## Полная очистка проекта
@echo "$(RED)🧹 Полная очистка проекта...$(RESET)"
@rm -rf .env
@rm -rf vault/
@rm -rf reports/
@rm -rf snapshots/
@echo "$(GREEN)✅ Проект очищен$(RESET)"
# =============================================================================
# ЗАГЛУШКИ ДЛЯ ПАРАМЕТРОВ
# =============================================================================
%:
@:
# =============================================================================
# ЗАГРУЗКА ПЕРЕМЕННЫХ ИЗ .env
# =============================================================================
ifneq (,$(wildcard .env))
include .env
export
endif