/
/
/
1#!/bin/bash
2# ==============================================================================
3# WireGuard Health Check Script
4# ==============================================================================
5#
6# Description: Comprehensive health check for WireGuard VPN service
7# Usage: ./wireguard-health-check.sh [full|quick|service|network|clients]
8#
9# This script is automatically generated by Ansible - DO NOT EDIT MANUALLY
10# Template: wireguard-health-check.sh.j2
11#
12# ==============================================================================
13
14set -euo pipefail
15
16# Configuration
17WG_CONTAINER="{{ wireguard_container_name }}"
18WG_WEB_PORT={{ wireguard_web_port }}
19WG_PORT={{ wireguard_port }}
20WG_CONFIG_DIR="{{ docker_base_path }}/wireguard/config"
21LOG_FILE="/var/log/wireguard-health.log"
22
23# Health check thresholds
24MAX_RESTARTS=10
25MAX_MEMORY_MB=512
26MAX_CPU_PERCENT=80
27
28# Exit codes
29SUCCESS=0
30WARNING=1
31CRITICAL=2
32UNKNOWN=3
33
34# Logging function
35log() {
36 echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "${LOG_FILE}"
37}
38
39# Check if container exists
40container_exists() {
41 docker inspect "${WG_CONTAINER}" >/dev/null 2>&1
42}
43
44# Check if container is running
45container_running() {
46 docker inspect -f '{{.State.Running}}' "${WG_CONTAINER}" 2>/dev/null | grep -q "true"
47}
48
49# Check container restart count
50check_restart_count() {
51 local restarts=$(docker inspect -f '{{.RestartCount}}' "${WG_CONTAINER}" 2>/dev/null || echo "0")
52
53 if [[ ${restarts} -gt ${MAX_RESTARTS} ]]; then
54 log "CRITICAL: Container restart count (${restarts}) exceeds threshold (${MAX_RESTARTS})"
55 return ${CRITICAL}
56 elif [[ ${restarts} -gt 0 ]]; then
57 log "WARNING: Container has restarted ${restarts} time(s)"
58 return ${WARNING}
59 else
60 log "OK: Container restart count: ${restarts}"
61 return ${SUCCESS}
62 fi
63}
64
65# Check container resource usage
66check_resources() {
67 local stats=$(docker stats "${WG_CONTAINER}" --no-stream --format "{{.MemUsage}}|{{.CPUPerc}}" 2>/dev/null || echo "N/A|N/A")
68 local memory_usage=$(echo "${stats}" | cut -d'|' -f1 | sed 's/[^0-9]*//g')
69 local cpu_percent=$(echo "${stats}" | cut -d'|' -f2 | sed 's/%//')
70
71 # Memory check
72 if [[ "${memory_usage}" != "N/A" ]] && [[ ${memory_usage} -gt ${MAX_MEMORY_MB}000000 ]]; then
73 local memory_mb=$((memory_usage / 1000000))
74 log "CRITICAL: Memory usage (${memory_mb}MB) exceeds threshold (${MAX_MEMORY_MB}MB)"
75 return ${CRITICAL}
76 fi
77
78 # CPU check
79 if [[ "${cpu_percent}" != "N/A" ]] && [[ $(printf "%.0f" "${cpu_percent}") -gt ${MAX_CPU_PERCENT} ]]; then
80 log "CRITICAL: CPU usage (${cpu_percent}%) exceeds threshold (${MAX_CPU_PERCENT}%)"
81 return ${CRITICAL}
82 fi
83
84 log "OK: Resource usage within limits"
85 return ${SUCCESS}
86}
87
88# Check Web UI accessibility
89check_web_ui() {
90 if curl -s -f "http://localhost:${WG_WEB_PORT}" >/dev/null; then
91 log "OK: Web UI is accessible"
92 return ${SUCCESS}
93 else
94 log "CRITICAL: Web UI is not accessible"
95 return ${CRITICAL}
96 fi
97}
98
99# Check WireGuard port
100check_wg_port() {
101 if nc -z -w 2 localhost ${WG_PORT} >/dev/null 2>&1; then
102 log "OK: WireGuard port ${WG_PORT} is open"
103 return ${SUCCESS}
104 else
105 log "CRITICAL: WireGuard port ${WG_PORT} is not accessible"
106 return ${CRITICAL}
107 fi
108}
109
110# Check configuration files
111check_config_files() {
112 local critical_files=(
113 "${WG_CONFIG_DIR}/wg-easy.db"
114 "${WG_CONFIG_DIR}/wg0.conf"
115 )
116
117 local missing_files=()
118
119 for file in "${critical_files[@]}"; do
120 if [[ ! -f "${file}" ]]; then
121 missing_files+=("${file}")
122 fi
123 done
124
125 if [[ ${#missing_files[@]} -gt 0 ]]; then
126 log "CRITICAL: Missing critical configuration files: ${missing_files[*]}"
127 return ${CRITICAL}
128 else
129 log "OK: All critical configuration files present"
130 return ${SUCCESS}
131 fi
132}
133
134# Check client count and status
135check_clients() {
136 if [[ -f "${WG_CONFIG_DIR}/wg-easy.db" ]]; then
137 local client_count=$(sqlite3 "${WG_CONFIG_DIR}/wg-easy.db" "SELECT COUNT(*) FROM clients;" 2>/dev/null || echo "0")
138
139 if [[ ${client_count} -eq 0 ]]; then
140 log "WARNING: No WireGuard clients configured"
141 return ${WARNING}
142 else
143 log "OK: ${client_count} WireGuard client(s) configured"
144
145 # Check for active clients
146 local active_clients=$(sqlite3 "${WG_CONFIG_DIR}/wg-easy.db" "SELECT COUNT(*) FROM clients WHERE enabled = 1;" 2>/dev/null || echo "0")
147 if [[ ${active_clients} -eq 0 ]]; then
148 log "WARNING: No active WireGuard clients"
149 return ${WARNING}
150 fi
151
152 return ${SUCCESS}
153 fi
154 else
155 log "WARNING: Cannot check clients - database file not found"
156 return ${WARNING}
157 fi
158}
159
160# Check Docker logs for errors
161check_logs() {
162 local error_count=$(docker logs "${WG_CONTAINER}" --since 1h 2>&1 | grep -i -E "(error|fail|exception|critical)" | wc -l)
163
164 if [[ ${error_count} -gt 5 ]]; then
165 log "CRITICAL: Found ${error_count} error messages in container logs (last hour)"
166 return ${CRITICAL}
167 elif [[ ${error_count} -gt 0 ]]; then
168 log "WARNING: Found ${error_count} error messages in container logs (last hour)"
169 return ${WARNING}
170 else
171 log "OK: No recent error messages in container logs"
172 return ${SUCCESS}
173 fi
174}
175
176# Perform full health check
177full_health_check() {
178 local overall_status=${SUCCESS}
179
180 log "Starting full WireGuard health check"
181
182 # Check container existence
183 if ! container_exists; then
184 log "CRITICAL: WireGuard container does not exist"
185 return ${CRITICAL}
186 fi
187
188 # Check container running state
189 if ! container_running; then
190 log "CRITICAL: WireGuard container is not running"
191 return ${CRITICAL}
192 fi
193
194 # Run all checks
195 check_restart_count || overall_status=${?}
196 check_resources || overall_status=${?}
197 check_web_ui || overall_status=${?}
198 check_wg_port || overall_status=${?}
199 check_config_files || overall_status=${?}
200 check_clients || overall_status=${?}
201 check_logs || overall_status=${?}
202
203 # Summary
204 case ${overall_status} in
205 ${SUCCESS})
206 log "HEALTH CHECK SUMMARY: All systems operational"
207 ;;
208 ${WARNING})
209 log "HEALTH CHECK SUMMARY: Operational with warnings"
210 ;;
211 ${CRITICAL})
212 log "HEALTH CHECK SUMMARY: Critical issues detected"
213 ;;
214 esac
215
216 return ${overall_status}
217}
218
219# Quick health check (basic checks only)
220quick_health_check() {
221 log "Starting quick WireGuard health check"
222
223 if ! container_exists || ! container_running; then
224 log "CRITICAL: Container not running"
225 return ${CRITICAL}
226 fi
227
228 if ! check_web_ui; then
229 return ${CRITICAL}
230 fi
231
232 if ! check_wg_port; then
233 return ${CRITICAL}
234 fi
235
236 log "QUICK CHECK SUMMARY: Service appears operational"
237 return ${SUCCESS}
238}
239
240# Show usage
241usage() {
242 cat << EOF
243WireGuard Health Check Script
244
245Usage: $0 [mode]
246
247Modes:
248 full Comprehensive health check (default)
249 quick Basic service availability check
250 service Container and service status only
251 network Network connectivity checks only
252 clients Client configuration checks only
253 help Show this help message
254
255Exit Codes:
256 0 - Success (all checks passed)
257 1 - Warning (non-critical issues)
258 2 - Critical (service impaired)
259 3 - Unknown (check could not complete)
260
261Examples:
262 $0 full
263 $0 quick
264 $0 service
265EOF
266}
267
268# Main execution
269main() {
270 local mode="${1:-full}"
271
272 case "${mode}" in
273 full)
274 full_health_check
275 ;;
276 quick)
277 quick_health_check
278 ;;
279 service)
280 check_restart_count
281 check_resources
282 check_logs
283 ;;
284 network)
285 check_web_ui
286 check_wg_port
287 ;;
288 clients)
289 check_clients
290 check_config_files
291 ;;
292 help|*)
293 usage
294 return ${SUCCESS}
295 ;;
296 esac
297}
298
299# Run main function with all arguments
300main "$@"
301
302# Capture and return the exit code
303exit $?