Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.

Commit 5d57840

Browse files
committed
feat: add local KVM/libvirt testing infrastructure with automated fixes
- Add complete local VM testing setup using OpenTofu and KVM/libvirt - Create infrastructure automation with Makefile targets for setup and testing - Add comprehensive libvirt troubleshooting and permission fixes - Implement automated AppArmor override for libvirt-qemu storage access - Add cloud-init configuration for Ubuntu 22.04 VMs with Docker setup - Create test suite for infrastructure validation and Torrust Tracker integration - Add detailed documentation with quick-start and troubleshooting guides - Configure markdownlint for consistent documentation formatting - Fix all markdown linting issues in core infrastructure documentation Infrastructure includes: - OpenTofu configuration for local VM deployment - Cloud-init setup with torrust user, Docker, and security hardening - Automated scripts for libvirt permission and storage pool fixes - Comprehensive test coverage for prerequisites, deployment, and integration - GitHub Actions workflow for CI/CD validation This enables reliable local testing before cloud deployment and provides automated solutions for common libvirt permission issues on Ubuntu/Debian.
1 parent 0ad886e commit 5d57840

24 files changed

+3273
-2
lines changed

.github/copilot-instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ Follow these conventions:
1818
- Uses hyphens to separate words, e.g., `1-add-new-feature`.
1919
- Ensure that shell scripts are POSIX-compliant.
2020
- Provide clear and concise documentation for any new features or changes.
21+
- Follow https://github.com/DavidAnson/markdownlint conventions for Markdown files.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: Infrastructure Tests
2+
3+
on:
4+
push:
5+
branches: [main, develop]
6+
paths:
7+
- "infrastructure/**"
8+
- "tests/infrastructure/**"
9+
- "Makefile"
10+
- ".github/workflows/infrastructure.yml"
11+
pull_request:
12+
branches: [main, develop]
13+
paths:
14+
- "infrastructure/**"
15+
- "tests/infrastructure/**"
16+
- "Makefile"
17+
- ".github/workflows/infrastructure.yml"
18+
19+
jobs:
20+
validate-infrastructure:
21+
runs-on: ubuntu-22.04
22+
23+
steps:
24+
- name: Checkout code
25+
uses: actions/checkout@v4
26+
27+
- name: Install OpenTofu
28+
run: |
29+
curl -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
30+
chmod +x install-opentofu.sh
31+
sudo ./install-opentofu.sh --install-method deb
32+
rm install-opentofu.sh
33+
tofu version
34+
35+
- name: Install yamllint
36+
run: |
37+
sudo apt-get update
38+
sudo apt-get install -y yamllint
39+
40+
- name: Validate OpenTofu syntax
41+
run: |
42+
cd infrastructure/terraform
43+
tofu init
44+
tofu validate
45+
tofu plan
46+
47+
- name: Validate cloud-init YAML
48+
run: |
49+
yamllint infrastructure/cloud-init/user-data.yaml
50+
yamllint infrastructure/cloud-init/network-config.yaml
51+
52+
- name: Test script permissions
53+
run: |
54+
test -x tests/infrastructure/test-local-setup.sh
55+
test -x tests/infrastructure/test-integration.sh
56+
57+
- name: Run syntax tests
58+
run: |
59+
make test-syntax
60+
61+
- name: Validate Makefile targets
62+
run: |
63+
make help
64+
make workflow-help
65+
66+
# Note: Full VM testing is not run in CI as it requires KVM/nested virtualization
67+
# which is not available in GitHub Actions runners
68+
documentation-check:
69+
runs-on: ubuntu-22.04
70+
71+
steps:
72+
- name: Checkout code
73+
uses: actions/checkout@v4
74+
75+
- name: Check documentation links
76+
run: |
77+
# Verify documentation files exist
78+
test -f docs/infrastructure/quick-start.md
79+
test -f docs/infrastructure/local-testing-setup.md
80+
test -f infrastructure/README.md
81+
82+
# Check for common documentation issues
83+
grep -q "Quick Start" docs/infrastructure/quick-start.md
84+
grep -q "OpenTofu" docs/infrastructure/local-testing-setup.md
85+
grep -q "make" README.md

.markdownlint.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"default": true,
3+
"MD013": {
4+
"line_length": 80
5+
},
6+
"MD031": true,
7+
"MD032": true,
8+
"MD040": true,
9+
"MD022": true,
10+
"MD009": true,
11+
"MD007": {
12+
"indent": 2
13+
},
14+
"MD026": false,
15+
"MD041": false,
16+
"MD034": false,
17+
"MD024": false,
18+
"MD033": false
19+
}

Makefile

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
# Makefile for Torrust Tracker Local Testing Infrastructure
2+
.PHONY: help init plan apply destroy test clean status ssh install-deps
3+
4+
# Default variables
5+
VM_NAME ?= torrust-tracker-demo
6+
TERRAFORM_DIR = infrastructure/terraform
7+
TESTS_DIR = tests/infrastructure
8+
9+
# Help target
10+
help: ## Show this help message
11+
@echo "Torrust Tracker Local Testing Infrastructure"
12+
@echo ""
13+
@echo "Available targets:"
14+
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-20s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
15+
16+
install-deps: ## Install required dependencies (Ubuntu/Debian)
17+
@echo "Installing dependencies..."
18+
sudo apt update
19+
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager genisoimage
20+
sudo usermod -aG libvirt $$USER
21+
sudo usermod -aG kvm $$USER
22+
sudo systemctl enable libvirtd
23+
sudo systemctl start libvirtd
24+
@echo "Setting up libvirt storage and permissions..."
25+
@sudo virsh pool-define-as default dir --target /var/lib/libvirt/images || true
26+
@sudo virsh pool-autostart default || true
27+
@sudo virsh pool-start default || true
28+
@sudo chown -R libvirt-qemu:libvirt /var/lib/libvirt/images/ || true
29+
@sudo chmod -R 755 /var/lib/libvirt/images/ || true
30+
@echo "Installing OpenTofu..."
31+
curl -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
32+
chmod +x install-opentofu.sh
33+
sudo ./install-opentofu.sh --install-method deb
34+
rm install-opentofu.sh
35+
@echo "Dependencies installed. Please log out and log back in for group changes to take effect."
36+
37+
init: ## Initialize OpenTofu
38+
@echo "Initializing OpenTofu..."
39+
cd $(TERRAFORM_DIR) && tofu init
40+
41+
plan: ## Show what OpenTofu will do
42+
@echo "Planning infrastructure changes..."
43+
@if [ -f $(TERRAFORM_DIR)/local.tfvars ]; then \
44+
cd $(TERRAFORM_DIR) && tofu plan -var-file="local.tfvars"; \
45+
else \
46+
echo "WARNING: No local.tfvars found. Please create it first with 'make setup-ssh-key'"; \
47+
exit 1; \
48+
fi
49+
50+
apply-minimal: ## Deploy VM with minimal cloud-init configuration
51+
@echo "Ensuring libvirt permissions are correct..."
52+
@$(MAKE) fix-libvirt
53+
@echo "Deploying VM with minimal configuration..."
54+
cd $(TERRAFORM_DIR) && tofu apply -var-file="local.tfvars" -var="use_minimal_config=true" -parallelism=1
55+
@echo "Fixing permissions after deployment..."
56+
@$(MAKE) fix-libvirt
57+
58+
apply: ## Deploy the VM
59+
@echo "Ensuring libvirt permissions are correct..."
60+
@$(MAKE) fix-libvirt
61+
@echo "Deploying VM..."
62+
@if [ -f $(TERRAFORM_DIR)/local.tfvars ]; then \
63+
echo "Using local SSH key configuration..."; \
64+
cd $(TERRAFORM_DIR) && tofu apply -var-file="local.tfvars" -parallelism=1; \
65+
else \
66+
echo "WARNING: No local.tfvars found. Creating with placeholder..."; \
67+
echo 'ssh_public_key = "REPLACE_WITH_YOUR_SSH_PUBLIC_KEY"' > $(TERRAFORM_DIR)/local.tfvars; \
68+
echo "Please edit $(TERRAFORM_DIR)/local.tfvars with your SSH public key and run 'make apply' again"; \
69+
exit 1; \
70+
fi
71+
@echo "Fixing permissions after deployment..."
72+
@$(MAKE) fix-libvirt
73+
74+
destroy: ## Destroy the VM
75+
@echo "Destroying VM..."
76+
cd $(TERRAFORM_DIR) && tofu destroy
77+
78+
status: ## Show current infrastructure status
79+
@echo "Infrastructure status:"
80+
cd $(TERRAFORM_DIR) && tofu show
81+
82+
ssh: ## SSH into the VM
83+
@echo "Connecting to VM..."
84+
@VM_IP=$$(cd $(TERRAFORM_DIR) && tofu output -raw vm_ip 2>/dev/null); \
85+
if [ -n "$$VM_IP" ]; then \
86+
echo "Connecting to $$VM_IP..."; \
87+
ssh torrust@$$VM_IP; \
88+
else \
89+
echo "Could not get VM IP. Is the VM deployed?"; \
90+
exit 1; \
91+
fi
92+
93+
test: ## Run all tests
94+
@echo "Running infrastructure tests..."
95+
$(TESTS_DIR)/test-local-setup.sh full-test
96+
97+
test-prereq: ## Test prerequisites only
98+
@echo "Testing prerequisites..."
99+
$(TESTS_DIR)/test-local-setup.sh prerequisites
100+
101+
check-libvirt: ## Check libvirt installation and permissions
102+
@echo "Checking libvirt setup..."
103+
@echo "1. Checking if libvirt service is running:"
104+
@sudo systemctl status libvirtd --no-pager -l || echo "libvirtd not running"
105+
@echo ""
106+
@echo "2. Checking user groups:"
107+
@groups | grep -q libvirt && echo "✓ User is in libvirt group" || echo "✗ User is NOT in libvirt group"
108+
@groups | grep -q kvm && echo "✓ User is in kvm group" || echo "✗ User is NOT in kvm group"
109+
@echo ""
110+
@echo "3. Testing libvirt access:"
111+
@virsh list --all >/dev/null 2>&1 && echo "✓ User can access libvirt" || echo "✗ User cannot access libvirt (try 'sudo virsh list')"
112+
@echo ""
113+
@echo "4. Checking default network:"
114+
@virsh net-list --all 2>/dev/null | grep -q default && echo "✓ Default network exists" || echo "✗ Default network missing"
115+
@echo ""
116+
@echo "5. Checking KVM support:"
117+
@test -r /dev/kvm && echo "✓ KVM device accessible" || echo "✗ KVM device not accessible"
118+
@echo ""
119+
@echo "If you see any ✗ marks, run 'make fix-libvirt' to attempt fixes"
120+
121+
fix-libvirt: ## Fix common libvirt permission issues
122+
@echo "Setting up user-friendly libvirt configuration..."
123+
@infrastructure/scripts/setup-user-libvirt.sh
124+
@echo "Attempting to fix libvirt permissions..."
125+
@echo "Adding user to required groups..."
126+
sudo usermod -aG libvirt $$USER
127+
sudo usermod -aG kvm $$USER
128+
@echo "Starting libvirt service..."
129+
sudo systemctl enable libvirtd
130+
sudo systemctl start libvirtd
131+
@echo "Checking if default network needs to be started..."
132+
@sudo virsh net-list --all | grep -q "default.*inactive" && sudo virsh net-start default || true
133+
@sudo virsh net-autostart default 2>/dev/null || true
134+
@echo ""
135+
@echo "✓ Fix attempt completed!"
136+
@echo "IMPORTANT: You need to log out and log back in (or run 'newgrp libvirt') for group changes to take effect"
137+
@echo "Then run 'make check-libvirt' to verify the fixes worked"
138+
139+
test-syntax: ## Test configuration syntax only
140+
@echo "Testing configuration syntax..."
141+
$(TESTS_DIR)/test-local-setup.sh syntax
142+
143+
test-integration: ## Run integration tests (requires deployed VM)
144+
@echo "Running integration tests..."
145+
$(TESTS_DIR)/test-integration.sh full-test
146+
147+
deploy-test: ## Deploy VM for testing (without cleanup)
148+
@echo "Deploying test VM..."
149+
$(TESTS_DIR)/test-local-setup.sh deploy
150+
151+
clean: ## Clean up temporary files
152+
@echo "Cleaning up..."
153+
rm -f $(TERRAFORM_DIR)/.terraform.lock.hcl
154+
rm -f $(TERRAFORM_DIR)/terraform.tfstate.backup
155+
rm -f install-opentofu.sh
156+
rm -f /tmp/torrust-infrastructure-test.log
157+
158+
clean-and-fix: ## Clean up all VMs and fix libvirt permissions
159+
@echo "Cleaning up VMs and fixing permissions..."
160+
@echo "1. Stopping and undefining any existing VMs:"
161+
@for vm in $$(virsh list --all --name 2>/dev/null | grep -v '^$$'); do \
162+
echo " Cleaning up VM: $$vm"; \
163+
virsh destroy $$vm 2>/dev/null || true; \
164+
virsh undefine $$vm 2>/dev/null || true; \
165+
done
166+
@echo "2. Removing OpenTofu state:"
167+
@cd $(TERRAFORM_DIR) && rm -f terraform.tfstate terraform.tfstate.backup .terraform.lock.hcl 2>/dev/null || true
168+
@echo "3. Cleaning libvirt images:"
169+
@sudo rm -f /var/lib/libvirt/images/torrust-tracker-demo* /var/lib/libvirt/images/ubuntu-22.04-base.qcow2 2>/dev/null || true
170+
@echo "4. Fixing libvirt setup:"
171+
@$(MAKE) fix-libvirt
172+
@echo "✓ Clean up complete. You can now run 'make apply' safely."
173+
174+
# New target for setting up SSH key
175+
setup-ssh-key: ## Setup local SSH key configuration
176+
@if [ -f $(TERRAFORM_DIR)/local.tfvars ]; then \
177+
echo "Local SSH configuration already exists at $(TERRAFORM_DIR)/local.tfvars"; \
178+
echo "Current configuration:"; \
179+
cat $(TERRAFORM_DIR)/local.tfvars; \
180+
else \
181+
echo "Creating local SSH key configuration..."; \
182+
echo 'ssh_public_key = "REPLACE_WITH_YOUR_SSH_PUBLIC_KEY"' > $(TERRAFORM_DIR)/local.tfvars; \
183+
echo ""; \
184+
echo "✓ Created $(TERRAFORM_DIR)/local.tfvars"; \
185+
echo ""; \
186+
echo "Next steps:"; \
187+
echo "1. Get your SSH public key:"; \
188+
echo " cat ~/.ssh/id_rsa.pub"; \
189+
echo " # or cat ~/.ssh/id_ed25519.pub"; \
190+
echo ""; \
191+
echo "2. Edit the file and replace the placeholder:"; \
192+
echo " vim $(TERRAFORM_DIR)/local.tfvars"; \
193+
echo ""; \
194+
echo "3. Deploy the VM:"; \
195+
echo " make apply"; \
196+
fi
197+
198+
restart-and-monitor: ## Destroy, deploy fresh, and monitor cloud-init
199+
@echo "🔄 Complete restart: destroying existing VM..."
200+
@$(MAKE) destroy || true
201+
@echo "🚀 Deploying fresh VM..."
202+
@$(MAKE) apply &
203+
@echo "⏳ Waiting 10 seconds for VM to start..."
204+
@sleep 10
205+
@echo "📡 Starting cloud-init monitoring..."
206+
@$(MAKE) monitor-cloud-init
207+
208+
fresh-start: restart-and-monitor ## Alias for restart-and-monitor
209+
210+
# Development targets
211+
dev-setup: install-deps init fix-libvirt setup-ssh-key ## Complete development setup
212+
@echo "Development environment setup complete!"
213+
@echo "Next steps:"
214+
@echo "1. Log out and log back in for group changes"
215+
@echo "2. Edit $(TERRAFORM_DIR)/local.tfvars with your SSH public key"
216+
@echo "3. Run 'make test-prereq' to verify setup"
217+
@echo "4. Run 'make apply' to deploy a VM"
218+
219+
quick-test: test-prereq test-syntax ## Quick test without VM deployment
220+
@echo "Quick tests completed!"
221+
222+
# Help for specific workflows
223+
workflow-help: ## Show common workflows
224+
@echo "Common workflows:"
225+
@echo ""
226+
@echo "1. First-time setup:"
227+
@echo " make dev-setup"
228+
@echo " # Log out and log back in"
229+
@echo " # Edit infrastructure/cloud-init/user-data.yaml to add your SSH key"
230+
@echo " make test-prereq"
231+
@echo ""
232+
@echo "2. Deploy and test:"
233+
@echo " make apply"
234+
@echo " make ssh"
235+
@echo " make destroy"
236+
@echo ""
237+
@echo "3. Run full test suite:"
238+
@echo " make test"
239+
@echo ""
240+
@echo "4. Run integration tests:"
241+
@echo " make apply"
242+
@echo " make test-integration"
243+
@echo " make destroy"
244+
@echo ""
245+
@echo "5. Development cycle:"
246+
@echo " make plan # Review changes"
247+
@echo " make apply # Deploy"
248+
@echo " make ssh # Test manually"
249+
@echo " make destroy # Clean up"
250+
251+
monitor-cloud-init: ## Monitor cloud-init progress in real-time
252+
@echo "Monitoring cloud-init progress..."
253+
@./infrastructure/scripts/monitor-cloud-init.sh
254+
255+
vm-restart: ## Restart the VM
256+
@echo "Restarting VM..."
257+
virsh shutdown $(VM_NAME)
258+
@echo "Waiting for shutdown..."
259+
@sleep 5
260+
virsh start $(VM_NAME)
261+
@echo "VM restarted"
262+
263+
# Advanced targets

0 commit comments

Comments
 (0)