# ============================================================================= # AnsibleTemplate - Универсальная система тестирования Ansible ролей # Автор: Сергей Антропов # Сайт: https://devops.org.ru # ============================================================================= SHELL := /bin/bash # ============================================================================= # ПЕРЕМЕННЫЕ # ============================================================================= # Цвета для вывода 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 # Глобальные переменные PROJECT_NAME ?= ansible-template VERSION ?= 0.1.0 AUTHOR ?= "Сергей Антропов" SITE ?= "https://devops.org.ru" DOCKER_IMAGE ?= inecs/ansible-controller:latest DOCKER_DIND_IMAGE ?= docker:27-dind CONTAINER_NAME ?= ansible-controller # Переменные для Docker Hub DOCKER_REGISTRY ?= inecs DOCKER_VERSION ?= latest DOCKER_IMAGES := ansible-controller alt-linux astra-linux redos rhel centos alma rocky .PHONY: role vault git docker-cmd presets controller help # ============================================================================= # КОМАНДЫ ДЛЯ РАБОТЫ С РОЛЯМИ # ============================================================================= role: @case "$(word 2, $(MAKECMDGOALS))" in \ lint) \ echo "🔍 Проверка синтаксиса ролей ..."; \ docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace -e ANSIBLE_FORCE_COLOR=1 $(DOCKER_IMAGE) bash -c "ansible-lint roles/ --config-file .ansible-lint || true"; \ echo "✅ Lint завершен";; \ test) \ echo "🚀 Тестирование ролей ..."; \ PRESET="default"; \ ARGS="$(wordlist 3,10,$(MAKECMDGOALS))"; \ if [ -n "$$ARGS" ]; then \ PRESET="$$(echo $$ARGS | cut -d' ' -f1)"; \ fi; \ echo "📋 Используется пресет: $$PRESET"; \ if [ ! -f "molecule/presets/$$PRESET.yml" ]; then \ echo "❌ Ошибка: Пресет '$$PRESET' не найден!"; \ echo "💡 Доступные пресеты:"; \ ls -1 molecule/presets/*.yml 2>/dev/null | sed 's|molecule/presets/||g' | sed 's|\.yml||g' | sed 's/^/ - /' || echo " ⚠️ Пресеты не найдены"; \ exit 1; \ fi; \ echo ""; \ if [ "$$PRESET" = "standart" ]; then \ ./scripts/test-standart.sh; \ else \ docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace \ -v /var/run/docker.sock:/var/run/docker.sock \ -e ANSIBLE_FORCE_COLOR=1 \ -e MOLECULE_PRESET=$$PRESET \ $(DOCKER_IMAGE) \ bash -c "cd molecule/default && ansible-playbook -i localhost, create.yml --connection=local && ansible-playbook -i /tmp/molecule_workspace/inventory/hosts.ini site.yml && ansible-playbook -i localhost, destroy.yml --connection=local" || echo "✅ Тестирование завершено"; \ fi;; \ deploy) \ echo "🚀 Развертывание ролей на реальные серверы..."; \ echo ""; \ if [ ! -f "inventory/hosts.ini" ]; then \ echo "❌ Ошибка: Файл inventory/hosts.ini не найден!"; \ echo "💡 Создайте файл inventory/hosts.ini с вашими серверами"; \ exit 1; \ fi; \ echo "📋 Используется inventory: inventory/hosts.ini"; \ echo "📄 Содержимое inventory:"; \ cat inventory/hosts.ini; \ echo ""; \ echo "🚀 Запуск развертывания..."; \ ansible-playbook -i inventory/hosts.ini deploy.yml --check; \ echo ""; \ read -p "Продолжить развертывание? (y/N): " confirm; \ if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \ ansible-playbook -i inventory/hosts.ini deploy.yml; \ else \ echo "❌ Развертывание отменено"; \ fi;; \ *) \ echo "🎯 Доступные команды:"; \ echo " make role test [preset] - протестировать роли"; \ echo " make role deploy - развернуть роли"; \ echo " make role lint - проверить синтаксис";; \ esac # ============================================================================= # КОМАНДЫ ДЛЯ РАБОТЫ С PRESET'АМИ # ============================================================================= presets: @case "$(word 2, $(MAKECMDGOALS))" in \ list) \ echo "📋 Доступные пресеты:"; \ echo ""; \ preset_count=0; \ for preset in molecule/presets/*.yml; do \ if [ -f "$$preset" ]; then \ preset_name=$$(basename "$$preset" .yml); \ preset_desc=$$(grep -E "^#description:" "$$preset" | head -1 | sed 's/^#description: *//' || echo "Описание отсутствует"); \ host_count=$$(grep -c "^- name:" "$$preset" 2>/dev/null || echo "?"); \ printf " 📄 %s - %s (%s хостов)\n" "$$preset_name" "$$preset_desc" "$$host_count"; \ preset_count=$$((preset_count + 1)); \ fi; \ done; \ if [ $$preset_count -eq 0 ]; then \ echo " ⚠️ Пресеты не найдены"; \ fi;; \ info) \ if [ -z "$(PRESET)" ]; then \ echo "❌ Ошибка: Укажите PRESET=имя_пресета"; \ echo "💡 Пример: make presets info PRESET=etcd-patroni"; \ exit 1; \ fi; \ if [ ! -f "molecule/presets/$(PRESET).yml" ]; then \ echo "❌ Ошибка: Пресет '$(PRESET)' не найден!"; \ echo "💡 Доступные пресеты:"; \ make presets list; \ exit 1; \ fi; \ echo "📋 Информация о пресете: $(PRESET)"; \ echo ""; \ echo "📄 Описание:"; \ grep -E "^#description:" "molecule/presets/$(PRESET).yml" | head -1 | sed 's/^#description: *//' || echo "Описание отсутствует"; \ echo ""; \ echo "🏠 Хосты:"; \ grep -E "^- name:" "molecule/presets/$(PRESET).yml" | sed 's/^- name: / - /' || echo "Хосты не найдены"; \ echo ""; \ echo "🌐 Сеть:"; \ grep -E "^docker_network:" "molecule/presets/$(PRESET).yml" | sed 's/^docker_network: / - /' || echo "Сеть не указана"; \ echo ""; \ echo "🐳 Образы:"; \ grep -E "^- " "molecule/presets/$(PRESET).yml" | grep -E "family:" | sed 's/.*family: / - /' || echo "Образы не найдены";; \ test) \ if [ -z "$(PRESET)" ]; then \ echo "❌ Ошибка: Укажите PRESET=имя_пресета"; \ echo "💡 Пример: make presets test PRESET=etcd-patroni"; \ exit 1; \ fi; \ if [ ! -f "molecule/presets/$(PRESET).yml" ]; then \ echo "❌ Ошибка: Пресет '$(PRESET)' не найден!"; \ echo "💡 Доступные пресеты:"; \ make presets list; \ exit 1; \ fi; \ echo "🚀 Тестирование с пресетом: $(PRESET)"; \ echo ""; \ docker run --rm --name $(CONTAINER_NAME) -v "$(PWD):/workspace" -w /workspace \ -v /var/run/docker.sock:/var/run/docker.sock \ -e ANSIBLE_FORCE_COLOR=1 \ -e MOLECULE_PRESET=$(PRESET) \ $(DOCKER_IMAGE) \ bash -c "cd molecule/default && molecule test" || echo "✅ Тестирование завершено";; \ *) \ echo "🎯 Доступные команды:"; \ echo ""; \ echo " 📋 make presets list - показать список preset'ов"; \ echo " 📄 make presets info - информация о preset'е"; \ echo " 🚀 make presets test - тест с preset'ом"; \ echo ""; \ echo "💡 Примеры:"; \ echo " make presets list"; \ echo " make presets info PRESET=etcd-patroni"; \ echo " make presets test PRESET=etcd-patroni";; \ esac # ============================================================================= # КОМАНДЫ ДЛЯ РАБОТЫ С VAULT # ============================================================================= vault: @case "$(word 2, $(MAKECMDGOALS))" in \ create) \ echo "🔐 Создание файла секретов..."; \ read -p "Введите имя файла (без .yml): " FILE; \ docker run --rm -it -v "$(PWD):/workspace" -w /workspace \ quay.io/ansible/creator-ee:latest \ ansible-vault create --encrypt-vault-id default --vault-password-file vault/.vault vault/$$FILE.yml;; \ edit) \ echo "🔐 Редактирование секретов..."; \ ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \ echo ""; \ read -p "Введите имя файла (без .yml): " FILE; \ docker run --rm -it -v "$(PWD):/workspace" -w /workspace \ quay.io/ansible/creator-ee:latest \ ansible-vault edit --vault-password-file vault/.vault vault/$$FILE.yml;; \ show) \ echo "🔐 Просмотр секретов..."; \ ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \ echo ""; \ read -p "Введите имя файла (без .yml): " FILE; \ docker run --rm -v "$(PWD):/workspace" -w /workspace \ quay.io/ansible/creator-ee:latest \ ansible-vault view --vault-password-file vault/.vault vault/$$FILE.yml;; \ delete) \ echo "🔐 Удаление секретов..."; \ ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \ echo ""; \ read -p "Введите имя файла (без .yml): " FILE; \ rm -f vault/$$FILE.yml;; \ encrypt) \ echo "🔐 Шифрование файла..."; \ ls -la vault/*.yml 2>/dev/null || echo "Нет файлов для шифрования"; \ echo ""; \ read -p "Введите имя файла (без .yml): " FILE; \ docker run --rm -v "$(PWD):/workspace" -w /workspace \ quay.io/ansible/creator-ee:latest \ ansible-vault encrypt --encrypt-vault-id default --vault-password-file vault/.vault vault/$$FILE.yml;; \ decrypt) \ echo "🔐 Расшифровка файла..."; \ ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \ echo ""; \ read -p "Введите имя файла (без .yml): " FILE; \ docker run --rm -v "$(PWD):/workspace" -w /workspace \ quay.io/ansible/creator-ee:latest \ ansible-vault decrypt --vault-password-file vault/.vault vault/$$FILE.yml;; \ rekey) \ echo "🔐 Смена пароля..."; \ ls -la vault/*.yml 2>/dev/null || echo "Нет зашифрованных файлов"; \ echo ""; \ read -p "Введите имя файла (без .yml): " FILE; \ docker run --rm -it -v "$(PWD):/workspace" -w /workspace \ quay.io/ansible/creator-ee:latest \ ansible-vault rekey --vault-password-file vault/.vault vault/$$FILE.yml;; \ check) \ echo "🔍 Проверка vault файлов..."; \ if [ ! -d "vault" ]; then \ echo "❌ Директория vault не найдена"; \ exit 1; \ fi; \ vault_files=$$(find vault -name "*.yml" -type f 2>/dev/null); \ if [ -z "$$vault_files" ]; then \ echo "⚠️ Vault файлы не найдены"; \ exit 0; \ fi; \ echo "📋 Найденные vault файлы:"; \ for file in $$vault_files; do \ echo " 📄 $$file"; \ done; \ echo ""; \ echo "🔍 Проверка структуры..."; \ for file in $$vault_files; do \ if grep -q "ANSIBLE_VAULT" "$$file"; then \ echo " ✅ $$file - зашифрован"; \ else \ echo " ⚠️ $$file - не зашифрован"; \ fi; \ done;; \ scan) \ echo "🔍 Поиск секретов в проекте..."; \ echo "📋 Поиск потенциальных секретов:"; \ find . -name "*.yml" -o -name "*.yaml" | grep -v ".git" | while read file; do \ if grep -qE "(password|secret|key|token|api_key)" "$$file" 2>/dev/null; then \ echo " ⚠️ $$file - содержит потенциальные секреты"; \ fi; \ done; \ echo ""; \ echo "💡 Рекомендации:"; \ echo " - Используйте ansible-vault для шифрования секретов"; \ echo " - Не храните секреты в открытом виде"; \ echo " - Регулярно проверяйте файлы на наличие секретов";; \ *) \ echo "🎯 Доступные команды:"; \ echo " make vault create - создать файл секретов"; \ echo " make vault edit - редактировать секреты"; \ echo " make vault show - показать секреты"; \ echo " make vault delete - удалить секреты"; \ echo " make vault encrypt - зашифровать файл"; \ echo " make vault decrypt - расшифровать файл"; \ echo " make vault rekey - сменить пароль"; \ echo " make vault check - проверка vault файлов"; \ echo " make vault scan - поиск секретов";; \ esac # ============================================================================= # КОМАНДЫ ДЛЯ РАБОТЫ С GIT # ============================================================================= git: @case "$(word 2, $(MAKECMDGOALS))" in \ push) \ echo "📤 Отправка изменений в репозиторий..."; \ git add .; \ git commit -m "Обновление проекта"; \ git push origin main;; \ pull) \ echo "📥 Получение изменений из репозитория..."; \ git pull origin main;; \ new) \ echo "🌿 Создание новой ветки..."; \ read -p "Введите имя ветки: " BRANCH; \ git checkout -b "$$BRANCH"; \ echo "✅ Ветка '$$BRANCH' создана";; \ *) \ echo "🎯 Доступные команды:"; \ echo " make git push - запушить изменения"; \ echo " make git pull - получить изменения"; \ echo " make git new - создать новую ветку";; \ esac # ============================================================================= # КОМАНДЫ ДЛЯ РАБОТЫ С DOCKER # ============================================================================= docker-cmd: @case "$(word 2, $(MAKECMDGOALS))" in \ prepare) \ echo "🔧 Подготовка Docker образов для Docker Hub..."; \ echo "📋 Registry: $(DOCKER_REGISTRY)"; \ echo "📋 Version: $(DOCKER_VERSION)"; \ echo "📋 Images: $(DOCKER_IMAGES)"; \ echo ""; \ echo "💡 Для работы с Docker Hub выполните:"; \ echo " docker login - авторизация в Docker Hub"; \ echo " make docker build - сборка образов"; \ echo " make docker push - отправка в Docker Hub";; \ build) \ echo "🐳 Сборка Docker образов..."; \ for image in $(DOCKER_IMAGES); do \ echo "🔨 Сборка $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \ cd dockerfiles/$$image && docker build -t $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION) .; \ done; \ echo "✅ Образы собраны";; \ push) \ echo "📤 Отправка Docker образов в Docker Hub..."; \ for image in $(DOCKER_IMAGES); do \ echo "📤 Отправка $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \ docker push $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION); \ done; \ echo "✅ Образы отправлены в Docker Hub";; \ pull) \ echo "📥 Загрузка Docker образов из Docker Hub..."; \ for image in $(DOCKER_IMAGES); do \ echo "📥 Загрузка $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \ docker pull $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION) || echo "⚠️ Образ $$image не найден в Docker Hub"; \ done; \ echo "✅ Загрузка завершена";; \ clean) \ echo "🧹 Очистка Docker образов..."; \ for image in $(DOCKER_IMAGES); do \ echo "🗑️ Удаление $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \ docker rmi $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION) 2>/dev/null || true; \ done; \ echo "✅ Образы очищены";; \ info) \ echo "📊 Информация об образах..."; \ for image in $(DOCKER_IMAGES); do \ if docker images | grep -q "$(DOCKER_REGISTRY)/$$image"; then \ echo "📦 $(DOCKER_REGISTRY)/$$image:$(DOCKER_VERSION)"; \ docker images | grep "$(DOCKER_REGISTRY)/$$image" | head -1; \ fi; \ done;; \ update) \ echo "🔄 Обновление всех образов..."; \ $(MAKE) docker pull; \ $(MAKE) docker build; \ $(MAKE) docker push; \ echo "✅ Все образы обновлены";; \ *) \ echo "🎯 Доступные команды:"; \ echo ""; \ echo " 🔧 make docker prepare - подготовка к работе с Docker Hub"; \ echo " 🐳 make docker build - собрать все образы"; \ echo " 📤 make docker push - отправить образы в Docker Hub"; \ echo " 📥 make docker pull - загрузить образы из Docker Hub"; \ echo " 🧹 make docker clean - удалить образы"; \ echo " 📊 make docker info - информация об образах"; \ echo " 🔄 make docker update - обновить все образы (pull + build + push)";; \ esac # ============================================================================= # КОМАНДЫ ДЛЯ РАБОТЫ С ANSIBLE-CONTROLLER # ============================================================================= controller: @case "$(word 2, $(MAKECMDGOALS))" in \ build) \ echo "🔨 Сборка ansible-controller..."; \ cd dockerfiles/ansible-controller && docker build -t $(DOCKER_REGISTRY)/ansible-controller:$(DOCKER_VERSION) .; \ echo "✅ ansible-controller собран";; \ run) \ echo "🚀 Запуск ansible-controller..."; \ cd dockerfiles/ansible-controller && docker-compose up -d; \ echo "✅ ansible-controller запущен";; \ stop) \ echo "🛑 Остановка ansible-controller..."; \ cd dockerfiles/ansible-controller && docker-compose down; \ echo "✅ ansible-controller остановлен";; \ *) \ echo "🎯 Доступные команды:"; \ echo ""; \ echo " 🔨 make controller build - собрать ansible-controller"; \ echo " 🚀 make controller run - запустить ansible-controller"; \ echo " 🛑 make controller stop - остановить ansible-controller";; \ esac # ============================================================================= # СПРАВКА # ============================================================================= help: @echo "==========================================" @echo "AnsibleTemplate - Универсальная система" @echo "тестирования Ansible ролей" @echo "==========================================" @echo "" @echo "📁 Структура проекта:" @echo " scripts/ - Скрипты автоматизации" @echo " inventory/ - Инвентори файлы" @echo " molecule/default/ - Molecule конфигурация" @echo " roles/ - Ansible роли" @echo " vault/ - Зашифрованные секреты" @echo "" @echo "🚀 ОСНОВНЫЕ КОМАНДЫ:" @echo " make role test [preset] - протестировать роли" @echo " make role deploy - развернуть роли" @echo " make role lint - проверить синтаксис" @echo "" @echo "📋 PRESET'Ы:" @echo " make presets list - показать все preset'ы" @echo " make presets test - тест с preset'ом" @echo "" @echo "🐳 DOCKER:" @echo " make docker-cmd build - собрать образы" @echo " make docker-cmd push - отправить в Docker Hub" @echo " make docker-cmd info - информация об образах" @echo "" @echo "🔐 VAULT:" @echo " make vault create - создать файл секретов" @echo " make vault check - проверка vault файлов" @echo "" @echo "📖 Подробная справка: make [команда]" @echo "==========================================" # Пустые цели для совместимости view create edit show delete lint deploy new advanced list info test build push pull clean prepare update run stop: @true