/
/
/
This repo is destined for my server automations and setup.
1---
2# Storage Services Playbook
3# Dedicated playbook for media automation and backup services
4
5- name: Storage Services Deployment
6 hosts: storage_servers
7 become: yes
8 gather_facts: yes
9
10 vars:
11 # Override defaults for storage-specific deployment
12 storage_enabled: true
13 backup_enabled: true
14
15 pre_tasks:
16 - name: Verify storage server requirements
17 assert:
18 that:
19 - storage_base_path is defined
20 - storage_docker_dir is defined
21 - ansible_default_ipv4.address is defined
22 - storage_user is defined
23 - storage_group is defined
24 fail_msg: "Storage server requirements not met. Check host variables."
25
26 - name: Validate storage paths exist and are accessible
27 block:
28 - name: Check storage base path
29 stat:
30 path: "{{ storage_base_path }}"
31 register: storage_base_stat
32 failed_when: not storage_base_stat.stat.exists
33
34 - name: Check storage base path permissions
35 assert:
36 that:
37 - storage_base_stat.stat.readable
38 - storage_base_stat.stat.writable
39 fail_msg: "Storage base path {{ storage_base_path }} is not readable/writable"
40
41 rescue:
42 - name: Display storage path error
43 debug:
44 msg: |
45 ERROR: Storage path validation failed!
46 Path: {{ storage_base_path }}
47 Ensure the storage array is mounted and accessible
48 Current mounts: {{ ansible_mounts | map(attribute='mount') | list }}
49
50 - name: Display storage deployment information
51 debug:
52 msg: |
53 ð Deploying Storage Services to: {{ inventory_hostname }}
54
55 ð Server Information:
56 - IP Address: {{ ansible_default_ipv4.address }}
57 - Storage Base: {{ storage_base_path }}
58 - Docker Directory: {{ storage_docker_dir }}
59 - User: {{ storage_user }}:{{ storage_group }}
60 - RAID Monitoring: Enabled
61 - GPU Acceleration: Disabled (CPU only)
62
63 ð¦ Services to Deploy:
64 {% if jellyfin_enabled | default(true) %}
65 - Jellyfin Media Server (Port {{ jellyfin_host_port | default(8096) }}) - CPU Hardware Acceleration
66 {% endif %}
67 {% if arr_stack_enabled | default(true) %}
68 - Arr Stack with Gluetun VPN:
69 * Sonarr TV (Port {{ sonarr_host_port | default(8989) }})
70 * Radarr Movies (Port {{ radarr_host_port | default(7878) }})
71 * Prowlarr Indexers (Port {{ prowlarr_host_port | default(9696) }})
72 * Readarr Books (Port {{ readarr_host_port | default(8787) }})
73 * Jellyseer (Port {{ jellyseer_host_port | default(5055) }}) - NEW!
74 {% endif %}
75 {% if calibre_enabled | default(true) %}
76 - Calibre Stack:
77 * Calibre Server (Port {{ calibre_server_host_port | default(8083) }})
78 * Calibre-Web (Port {{ calibre_web_host_port | default(8084) }})
79 {% endif %}
80 {% if restic_backup_server_enabled | default(true) %}
81 - Restic Backup Server (Port {{ restic_backup_host_port | default(8000) }})
82 {% endif %}
83
84 ð¡ï¸ Monitoring:
85 - RAID Health Monitoring: Enabled (mdadm)
86 - SMART Monitoring: Enabled
87 - Service Health Checks: Comprehensive
88
89 ð Directory Structure:
90 - Service configs: {{ storage_docker_dir }}/[service-name]
91 - Environment files: {{ storage_docker_dir }}/[service-name]/.env
92 - Individual service directories for ARR stack
93
94 roles:
95 # Core prerequisites
96 - role: user
97 tags: ['core', 'user']
98
99 - role: system
100 tags: ['core', 'system']
101
102 - role: geerlingguy.docker
103 tags: ['core', 'docker']
104
105 - role: geerlingguy.security
106 tags: ['core', 'security']
107
108 - role: docker-framework
109 tags: ['docker-framework', 'core', 'docker']
110
111 # Storage-specific services
112 - role: storage
113 tags: ['storage', 'media', 'backup']
114
115 # RAID monitoring for storage server
116 - role: nas
117 tags: ['storage', 'monitoring', 'raid']
118 vars:
119 # Only run monitoring tasks from NAS role
120 nas_nfs_enabled: false
121 nas_network_bonding_enabled: false
122 nas_performance_tuning_enabled: false
123 nas_backup_integration: false
124 nas_enable_runner_exports: false
125 nas_monitoring_enabled: true
126 nas_raid_monitoring: true
127 nas_smartmontools_enabled: true
128
129 # Backup role for system-level backups
130 - role: backup
131 tags: ['system-backup']
132 when: backup_enabled | default(true)
133
134 post_tasks:
135 - name: Verify core services are running
136 systemd:
137 name: "{{ item }}"
138 state: started
139 enabled: yes
140 loop:
141 - docker
142 - mdmonitor
143 - smartd
144 tags: ['verification', 'monitoring']
145
146 - name: Verify RAID monitoring is active
147 command: systemctl is-active mdmonitor
148 register: mdmonitor_status
149 changed_when: false
150 ignore_errors: true
151 tags: ['verification', 'raid']
152
153 - name: Verify SMART monitoring is active
154 command: systemctl is-active smartd
155 register: smartd_status
156 changed_when: false
157 ignore_errors: true
158 tags: ['verification', 'smart']
159
160 - name: Generate storage access summary
161 template:
162 src: "{{ role_path }}/templates/storage-access-summary.txt.j2"
163 dest: "{{ storage_docker_dir }}/storage-access-info.txt"
164 owner: "{{ storage_user | default(ansible_user) }}"
165 group: "{{ storage_group | default(ansible_user) }}"
166 mode: '0644'
167 vars:
168 role_path: "roles/storage"
169 tags: ['summary']
170
171 - name: Wait for all storage services to be healthy
172 uri:
173 url: "http://{{ ansible_default_ipv4.address }}:{{ item.port }}{{ item.path | default('') }}"
174 method: GET
175 status_code: [200, 302, 401] # Some services redirect or require auth
176 loop:
177 - { port: "{{ jellyfin_host_port | default(8096) }}", path: "/health", service: "Jellyfin" }
178 - { port: "{{ sonarr_host_port | default(8989) }}", path: "/ping", service: "Sonarr" }
179 - { port: "{{ radarr_host_port | default(7878) }}", path: "/ping", service: "Radarr" }
180 - { port: "{{ prowlarr_host_port | default(9696) }}", path: "/ping", service: "Prowlarr" }
181 - { port: "{{ readarr_host_port | default(8787) }}", path: "/ping", service: "Readarr" }
182 - { port: "{{ jellyseer_host_port | default(5055) }}", path: "/", service: "Jellyseer" }
183 - { port: "{{ calibre_web_host_port | default(8084) }}", path: "/", service: "Calibre-Web" }
184 retries: 12
185 delay: 10
186 ignore_errors: yes
187 tags: ['verification', 'health-check']
188
189 - name: Display deployment completion summary
190 debug:
191 msg: |
192 ð Storage Services Deployment Complete!
193
194 Server: {{ inventory_hostname }} ({{ ansible_default_ipv4.address }})
195
196 ð Monitoring Status:
197 - RAID Monitoring: {{ 'Active' if mdmonitor_status.rc == 0 else 'Inactive' }}
198 - SMART Monitoring: {{ 'Active' if smartd_status.rc == 0 else 'Inactive' }}
199 - Docker: Active
200
201 ð Access Information:
202 {% if jellyfin_enabled | default(true) %}
203 - Jellyfin: http://{{ ansible_default_ipv4.address }}:{{ jellyfin_host_port | default(8096) }} (CPU Hardware Acceleration)
204 {% endif %}
205 {% if arr_stack_enabled | default(true) %}
206 - Sonarr: http://{{ ansible_default_ipv4.address }}:{{ sonarr_host_port | default(8989) }}
207 - Radarr: http://{{ ansible_default_ipv4.address }}:{{ radarr_host_port | default(7878) }}
208 - Prowlarr: http://{{ ansible_default_ipv4.address }}:{{ prowlarr_host_port | default(9696) }}
209 - Readarr: http://{{ ansible_default_ipv4.address }}:{{ readarr_host_port | default(8787) }}
210 - Jellyseer: http://{{ ansible_default_ipv4.address }}:{{ jellyseer_host_port | default(5055) }} (NEW!)
211 {% endif %}
212 {% if calibre_enabled | default(true) %}
213 - Calibre-Web: http://{{ ansible_default_ipv4.address }}:{{ calibre_web_host_port | default(8084) }}
214 {% endif %}
215 {% if restic_backup_server_enabled | default(true) %}
216 - Restic Backup: http://{{ ansible_default_ipv4.address }}:{{ restic_backup_host_port | default(8000) }}
217 {% endif %}
218
219 ð File Locations:
220 - Docker Configs: {{ storage_docker_dir }}
221 - Media Storage: {{ storage_base_path }}/media
222 - Downloads: {{ storage_base_path }}/downloads
223 - Backups: {{ storage_base_path }}/backups
224 - Access Info: {{ storage_docker_dir }}/storage-access-info.txt
225 - Health Check: {{ storage_docker_dir }}/storage-health-check.sh
226 - RAID Monitoring: /usr/local/bin/raid-health-check.sh
227 - SMART Monitoring: /etc/smartd.conf
228
229 ð¡ï¸ Monitoring Commands:
230 - RAID Status: cat /proc/mdstat
231 - RAID Health: /usr/local/bin/raid-health-check.sh
232 - SMART Status: smartctl -a /dev/sdX
233 - Service Health: {{ storage_docker_dir }}/storage-health-check.sh
234
235 ð§ Next Steps:
236 1. Configure VPN credentials in vault for Gluetun
237 2. Set up indexers in Prowlarr
238 3. Configure quality profiles in Arr applications
239 4. Add media libraries in Jellyfin
240 5. Import books to Calibre library
241 6. Configure Jellyseer with Jellyfin and Arr app integration
242 7. Set up backup clients using: {{ storage_docker_dir }}/restic-server/client-setup-example.sh
243
244 â¡ Management Commands:
245 - Health Check: {{ storage_docker_dir }}/storage-health-check.sh
246 - Restart All: docker restart $(docker ps -q)
247 - View Logs: docker compose logs -f (in service directories)
248 - Monitor RAID: watch cat /proc/mdstat
249
250 ð¡ Important Notes:
251 - RAID arrays monitored every 5 minutes
252 - SMART monitoring active for drive health
253 - All services configured for CPU-only operation (no GPU)
254 - Individual service directories for ARR stack components
255 tags: ['always']