/
/
/
Ansible role that provisions my storage server.
1#!/bin/bash
2# Storage Services Status Check
3# Auto-generated by Ansible Storage Role
4
5set -euo pipefail
6
7# Colors for output
8RED='\033[0;31m'
9GREEN='\033[0;32m'
10YELLOW='\033[1;33m'
11BLUE='\033[0;34m'
12NC='\033[0m' # No Color
13
14# Configuration
15SERVICES=(
16{% if jellyfin_enabled %}
17 "jellyfin:{{ jellyfin_port }}:{{ jellyfin_data_dir }}/docker-compose.yml"
18{% endif %}
19{% if arr_stack_enabled %}
20 "arr-stack:{{ sonarr_port }}:{{ arr_config_dir }}/docker-compose.yml"
21{% endif %}
22{% if calibre_enabled %}
23 "calibre-stack:{{ calibre_server_port }}:{{ calibre_config_dir }}/docker-compose.yml"
24{% endif %}
25{% if restic_backup_server_enabled %}
26 "restic-server:{{ restic_backup_port }}:{{ restic_backup_config_dir }}/docker-compose.yml"
27{% endif %}
28)
29
30echo -e "${BLUE}===========================================${NC}"
31echo -e "${BLUE} STORAGE SERVICES STATUS CHECK ${NC}"
32echo -e "${BLUE}===========================================${NC}"
33echo ""
34
35# Check Docker daemon
36echo -e "${BLUE}Docker Status:${NC}"
37if systemctl is-active --quiet docker; then
38 echo -e " Docker daemon: ${GREEN}RUNNING${NC}"
39else
40 echo -e " Docker daemon: ${RED}STOPPED${NC}"
41 exit 1
42fi
43
44# Check Docker network
45if docker network inspect {{ storage_docker_network }} >/dev/null 2>&1; then
46 echo -e " Docker network: ${GREEN}EXISTS${NC} ({{ storage_docker_network }})"
47else
48 echo -e " Docker network: ${RED}MISSING${NC} ({{ storage_docker_network }})"
49fi
50echo ""
51
52# Check directory accessibility
53echo -e "${BLUE}Directory Status:${NC}"
54check_directory() {
55 local dir="$1"
56 local description="$2"
57
58 echo -n " $description... "
59 if [ -d "$dir" ] && [ -r "$dir" ] && [ -w "$dir" ]; then
60 echo -e "${GREEN}ACCESSIBLE${NC}"
61 else
62 echo -e "${RED}INACCESSIBLE${NC}"
63 fi
64}
65
66check_directory "{{ storage_docker_dir }}" "Docker config"
67check_directory "{{ storage_base_path }}" "Storage base"
68check_directory "{{ arr_downloads_dir }}" "Downloads"
69check_directory "{{ storage_base_path }}/media" "Media"
70echo ""
71
72# Check service containers and ports
73echo -e "${BLUE}Services:${NC}"
74for service_info in "${SERVICES[@]}"; do
75 IFS=':' read -r service_name service_port compose_file <<< "$service_info"
76
77 # Check if compose file exists
78 if [[ ! -f "$compose_file" ]]; then
79 echo -e " $service_name: ${RED}NO CONFIG${NC} ($compose_file missing)"
80 continue
81 fi
82
83 # Check container status
84 container_status="UNKNOWN"
85 if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then
86 if cd "$(dirname "$compose_file")" && docker compose ps -q | grep -q .; then
87 if cd "$(dirname "$compose_file")" && docker compose ps | grep -q "Up"; then
88 container_status="${GREEN}RUNNING${NC}"
89 else
90 container_status="${RED}STOPPED${NC}"
91 fi
92 else
93 container_status="${RED}NOT FOUND${NC}"
94 fi
95 fi
96
97 # Check port accessibility
98 port_status="${RED}CLOSED${NC}"
99 if timeout 3 bash -c "echo >/dev/tcp/localhost/$service_port" 2>/dev/null; then
100 port_status="${GREEN}OPEN${NC}"
101 fi
102
103 echo -e " $service_name: Container $container_status | Port $service_port $port_status"
104done
105echo ""
106
107# Check disk usage
108echo -e "${BLUE}Storage Usage:${NC}"
109echo -e " Service directories: $(du -sh /docker/* 2>/dev/null | awk '{total+=$1}END{print total"K"}')"
110echo -e " Individual services:"
111{% if jellyfin_enabled %}
112echo -e " Jellyfin: $(du -sh {{ jellyfin_data_dir }} 2>/dev/null | cut -f1) ({{ jellyfin_data_dir }})"
113{% endif %}
114{% if arr_stack_enabled %}
115echo -e " Arr Stack: $(du -sh {{ arr_config_dir }} 2>/dev/null | cut -f1) ({{ arr_config_dir }})"
116{% endif %}
117{% if calibre_enabled %}
118echo -e " Calibre Stack: $(du -sh {{ calibre_config_dir }} 2>/dev/null | cut -f1) ({{ calibre_config_dir }})"
119{% endif %}
120{% if restic_backup_server_enabled %}
121echo -e " Restic Server: $(du -sh {{ restic_backup_config_dir }} 2>/dev/null | cut -f1) ({{ restic_backup_config_dir }})"
122{% endif %}
123echo ""
124
125# Check recent logs for errors
126echo -e "${BLUE}Recent Issues:${NC}"
127error_count=0
128for service_info in "${SERVICES[@]}"; do
129 IFS=':' read -r service_name service_port compose_file <<< "$service_info"
130 if [[ -f "$compose_file" ]]; then
131 cd "$(dirname "$compose_file")"
132 if errors=$(docker compose logs --tail=10 2>/dev/null | grep -i "error\\|failed\\|exception" | wc -l); then
133 if [[ $errors -gt 0 ]]; then
134 echo -e " $service_name: ${YELLOW}$errors errors${NC} in recent logs"
135 ((error_count++))
136 fi
137 fi
138 fi
139done
140
141if [[ $error_count -eq 0 ]]; then
142 echo -e " ${GREEN}No recent errors detected${NC}"
143fi
144echo ""
145
146# System resource usage
147echo -e "${BLUE}System Resources:${NC}"
148echo -e " CPU Usage: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)%"
149echo -e " Memory Usage: $(free | grep Mem | awk '{printf("%.1f%%", $3/$2 * 100.0)}')"
150echo -e " Disk Usage (root): $(df -h / | awk 'NR==2{printf "%s", $5}')"
151echo ""
152
153echo -e "${BLUE}===========================================${NC}"
154echo -e "${BLUE}Status check completed at $(date)${NC}"
155echo -e "${BLUE}===========================================${NC}"
156
157# Exit codes for automation
158# 0: All services healthy
159# 1: Critical issues (Docker down, etc.)
160# 2: Some services have issues but system functional
161exit_code=0
162for service_info in "${SERVICES[@]}"; do
163 IFS=':' read -r service_name service_port compose_file <<< "$service_info"
164 if ! timeout 3 bash -c "echo >/dev/tcp/localhost/$service_port" 2>/dev/null; then
165 exit_code=2
166 fi
167done
168
169exit $exit_code