.PHONY: help bootstrap lint test check apply dev local clean status .DEFAULT_GOAL := help ## Colors for output BOLD := \033[1m RED := \033[31m GREEN := \033[32m YELLOW := \033[33m BLUE := \033[34m RESET := \033[0m help: ## Show this help message @echo "$(BOLD)Ansible Development Environment$(RESET)" @echo "" @echo "$(BOLD)Available commands:$(RESET)" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " $(BLUE)%-15s$(RESET) %s\n", $$1, $$2}' @echo "" @echo "$(BOLD)Examples:$(RESET)" @echo " make bootstrap # Set up dependencies" @echo " make check # Dry run all hosts" @echo " make apply # Run on all dev hosts" @echo " make dev HOST=dev01 # Run on specific host" @echo " make local # Run local playbook" @echo " make maintenance # Run maintenance on all hosts" @echo " make maintenance GROUP=dev # Run maintenance on dev group" @echo " make maintenance HOST=dev01 # Run maintenance on specific host" @echo " make maintenance CHECK=true # Dry-run maintenance on all hosts" @echo "" bootstrap: ## Install required collections and dependencies @echo "$(YELLOW)Installing Ansible collections...$(RESET)" ansible-galaxy collection install -r collections/requirements.yml @echo "$(GREEN)✓ Collections installed$(RESET)" lint: ## Run ansible-lint on all playbooks and roles @echo "$(YELLOW)Running ansible-lint...$(RESET)" ansible-lint @echo "$(GREEN)✓ Linting completed$(RESET)" test: lint ## Run all tests (lint + syntax check) @echo "$(YELLOW)Testing playbook syntax...$(RESET)" ansible-playbook dev-playbook.yml --syntax-check ansible-playbook local-playbook.yml --syntax-check ansible-playbook maintenance-playbook.yml --syntax-check @echo "$(GREEN)✓ Syntax check passed$(RESET)" check: ## Dry-run the development playbook (--check mode) @echo "$(YELLOW)Running dry-run on development hosts...$(RESET)" ansible-playbook dev-playbook.yml --check --diff check-local: ## Dry-run the local playbook @echo "$(YELLOW)Running dry-run on localhost...$(RESET)" ansible-playbook local-playbook.yml --check --diff -K apply: ## Run the development playbook on all dev hosts @echo "$(YELLOW)Applying development playbook...$(RESET)" ansible-playbook dev-playbook.yml local: ## Run the local playbook on localhost @echo "$(YELLOW)Applying local playbook...$(RESET)" ansible-playbook local-playbook.yml -K # Host-specific targets dev: ## Run on specific host (usage: make dev HOST=dev01) ifndef HOST @echo "$(RED)Error: HOST parameter required$(RESET)" @echo "Usage: make dev HOST=dev01" @exit 1 endif @echo "$(YELLOW)Running on host: $(HOST)$(RESET)" ansible-playbook dev-playbook.yml --limit $(HOST) # Tag-based execution security: ## Run only security-related roles @echo "$(YELLOW)Running security roles...$(RESET)" ansible-playbook dev-playbook.yml --tags security # Unified maintenance target with intelligent parameter detection maintenance: ## Run maintenance (usage: make maintenance [GROUP=dev] [HOST=dev01] [SERIAL=1] [CHECK=true]) @$(MAKE) _maintenance-run _maintenance-run: @# Determine target and build command @TARGET="all"; \ ANSIBLE_CMD="ansible-playbook maintenance-playbook.yml"; \ DESCRIPTION="all hosts"; \ NEED_SUDO=""; \ \ if [ -n "$(HOST)" ]; then \ TARGET="host $(HOST)"; \ ANSIBLE_CMD="$$ANSIBLE_CMD --limit $(HOST)"; \ DESCRIPTION="host $(HOST)"; \ if [ "$(HOST)" = "localhost" ]; then \ NEED_SUDO="-K"; \ fi; \ elif [ -n "$(GROUP)" ]; then \ TARGET="$(GROUP) group"; \ ANSIBLE_CMD="$$ANSIBLE_CMD -e target_group=$(GROUP)"; \ DESCRIPTION="$(GROUP) group"; \ if [ "$(GROUP)" = "local" ]; then \ NEED_SUDO="-K"; \ fi; \ else \ NEED_SUDO="-K"; \ fi; \ \ if [ -n "$(SERIAL)" ]; then \ ANSIBLE_CMD="$$ANSIBLE_CMD -e maintenance_serial=$(SERIAL)"; \ DESCRIPTION="$$DESCRIPTION (serial=$(SERIAL))"; \ fi; \ \ if [ "$(CHECK)" = "true" ]; then \ ANSIBLE_CMD="$$ANSIBLE_CMD --check --diff"; \ echo "$(YELLOW)Dry-run maintenance on $$DESCRIPTION...$(RESET)"; \ else \ echo "$(YELLOW)Running maintenance on $$DESCRIPTION...$(RESET)"; \ fi; \ \ if [ -n "$(GROUP)" ] && [ "$(GROUP)" != "dev" ] && [ "$(GROUP)" != "local" ]; then \ echo "$(BLUE)Available groups: dev, gitea, portainer, homepage, ansible, local$(RESET)"; \ fi; \ \ $$ANSIBLE_CMD $$NEED_SUDO # Legacy/convenience aliases maintenance-dev: ## Run maintenance on dev group (legacy alias) @$(MAKE) maintenance GROUP=dev maintenance-all: ## Run maintenance on all hosts (legacy alias) @$(MAKE) maintenance maintenance-check: ## Dry-run maintenance (legacy alias, usage: make maintenance-check [GROUP=dev]) @$(MAKE) maintenance CHECK=true GROUP=$(GROUP) docker: ## Install/configure Docker only @echo "$(YELLOW)Running Docker setup...$(RESET)" ansible-playbook dev-playbook.yml --tags docker shell: ## Configure shell only @echo "$(YELLOW)Running shell configuration...$(RESET)" ansible-playbook dev-playbook.yml --tags shell apps: ## Install applications only @echo "$(YELLOW)Installing applications...$(RESET)" ansible-playbook dev-playbook.yml --tags apps # Connectivity targets ping: ## Ping hosts with colored output (usage: make ping [GROUP=dev] [HOST=dev01]) ifdef HOST @echo "$(YELLOW)Pinging host: $(HOST)$(RESET)" @ansible $(HOST) -m ping --one-line | while read line; do \ if echo "$$line" | grep -q "SUCCESS"; then \ echo "$(GREEN)✓ $$line$(RESET)"; \ elif echo "$$line" | grep -q "UNREACHABLE"; then \ echo "$(RED)✗ $$line$(RESET)"; \ else \ echo "$(YELLOW)? $$line$(RESET)"; \ fi; \ done else ifdef GROUP @echo "$(YELLOW)Pinging $(GROUP) group...$(RESET)" @ansible $(GROUP) -m ping --one-line | while read line; do \ if echo "$$line" | grep -q "SUCCESS"; then \ echo "$(GREEN)✓ $$line$(RESET)"; \ elif echo "$$line" | grep -q "UNREACHABLE"; then \ echo "$(RED)✗ $$line$(RESET)"; \ else \ echo "$(YELLOW)? $$line$(RESET)"; \ fi; \ done else @echo "$(YELLOW)Pinging all hosts...$(RESET)" @ansible all -m ping --one-line | while read line; do \ if echo "$$line" | grep -q "SUCCESS"; then \ echo "$(GREEN)✓ $$line$(RESET)"; \ elif echo "$$line" | grep -q "UNREACHABLE"; then \ echo "$(RED)✗ $$line$(RESET)"; \ else \ echo "$(YELLOW)? $$line$(RESET)"; \ fi; \ done endif facts: ## Gather facts from all hosts @echo "$(YELLOW)Gathering facts...$(RESET)" ansible all -m setup --tree /tmp/facts clean: ## Clean up ansible artifacts @echo "$(YELLOW)Cleaning up artifacts...$(RESET)" rm -rf .ansible/facts/ find . -name "*.retry" -delete @echo "$(GREEN)✓ Cleanup completed$(RESET)" # Debug targets debug: ## Run with debug output enabled @echo "$(YELLOW)Running with debug output...$(RESET)" ansible-playbook dev-playbook.yml -e "ansible_debug_output=true" verbose: ## Run with verbose output @echo "$(YELLOW)Running with verbose output...$(RESET)" ansible-playbook dev-playbook.yml -vv # Quick development workflow quick: test check ## Quick test and check before applying @echo "$(GREEN)✓ Ready to apply changes$(RESET)" # Vault management edit-vault: ## Edit encrypted host vars (usage: make edit-vault HOST=dev01) ifndef HOST @echo "$(RED)Error: HOST parameter required$(RESET)" @echo "Usage: make edit-vault HOST=dev01" @exit 1 endif ansible-vault edit host_vars/$(HOST).yml test-connectivity: ## Test network connectivity and SSH access to all hosts @echo "$(BOLD)Testing Connectivity to All Hosts$(RESET)" @echo "" @echo "$(YELLOW)1. Testing network connectivity (ping)...$(RESET)" @for host in giteaVM portainerVM homepageVM dev01 bottom debianDesktopVM; do \ ip=$$(ansible-inventory --list | jq -r ".$$host.ansible_host // empty" 2>/dev/null || echo "unknown"); \ if [ "$$ip" != "unknown" ] && [ "$$ip" != "null" ] && [ "$$ip" != "" ]; then \ echo -n " $$host ($$ip): "; \ if ping -c 1 -W 2 $$ip >/dev/null 2>&1; then \ echo "$(GREEN)✓ Network OK$(RESET)"; \ else \ echo "$(RED)✗ Network FAIL$(RESET)"; \ fi; \ else \ echo " $$host: $(YELLOW)? IP not found in inventory$(RESET)"; \ fi; \ done @echo "" @echo "$(YELLOW)2. Testing SSH connectivity...$(RESET)" @ansible all -m ping --one-line 2>/dev/null | while read line; do \ if echo "$$line" | grep -q "SUCCESS"; then \ echo " $(GREEN)✓ $$line$(RESET)"; \ elif echo "$$line" | grep -q "UNREACHABLE"; then \ echo " $(RED)✗ $$line$(RESET)"; \ else \ echo " $(YELLOW)? $$line$(RESET)"; \ fi; \ done || true @echo "" @echo "$(YELLOW)3. SSH key status...$(RESET)" @if [ -f ~/.ssh/id_rsa.pub ]; then \ echo " $(GREEN)✓ SSH public key found: ~/.ssh/id_rsa.pub$(RESET)"; \ elif [ -f ~/.ssh/id_ed25519.pub ]; then \ echo " $(GREEN)✓ SSH public key found: ~/.ssh/id_ed25519.pub$(RESET)"; \ else \ echo " $(RED)✗ No SSH public key found$(RESET)"; \ echo " $(YELLOW) Run: ssh-keygen -t ed25519 -C 'your_email@example.com'$(RESET)"; \ fi @echo "" @echo "$(BOLD)Troubleshooting Tips:$(RESET)" @echo " • For network failures: Check if VMs are running and IPs are correct" @echo " • For SSH failures: Copy your SSH key to the target hosts" @echo " • Run: ssh-copy-id user@host (for each failing host)" @echo " • Or: make copy-ssh-key HOST=hostname" copy-ssh-key: ## Copy SSH key to specific host (usage: make copy-ssh-key HOST=giteaVM) ifndef HOST @echo "$(RED)Error: HOST parameter required$(RESET)" @echo "Usage: make copy-ssh-key HOST=giteaVM" @exit 1 endif @echo "$(YELLOW)Copying SSH key to $(HOST)...$(RESET)" @ip=$$(ansible-inventory --list | jq -r "._meta.hostvars.$(HOST).ansible_host // empty" 2>/dev/null); \ user=$$(ansible-inventory --list | jq -r "._meta.hostvars.$(HOST).ansible_user // empty" 2>/dev/null); \ if [ -n "$$ip" ] && [ "$$ip" != "null" ] && [ -n "$$user" ] && [ "$$user" != "null" ]; then \ echo "Target: $$user@$$ip"; \ ssh-copy-id $$user@$$ip; \ else \ echo "$(RED)Could not determine IP or user for $(HOST)$(RESET)"; \ echo "Check your inventory and host_vars"; \ fi