/
/
/
This repo is destined for my server automations and setup.
1---
2# ============================================================================
3# Snapcast Client Deployment Playbook
4# ============================================================================
5#
6# This playbook deploys Snapcast clients to HiFi nodes in two stages:
7# 1. Generic server setup on all hifi-nodes (system, docker, security, user)
8# 2. Snapcast client configuration with individual parameters per node
9#
10# Usage:
11# ansible-playbook snapcast.yml
12#
13# ============================================================================
14
15# STAGE 1: Generic server setup on all hifi-nodes
16- name: "Generic Server Setup - HiFi Nodes Group"
17 hosts: hifi_nodes
18 become: true
19 gather_facts: true
20
21 # Load configuration from group_vars and host_vars
22 # Override with command line variables as needed
23
24 pre_tasks:
25 - name: Display deployment information
26 debug:
27 msg: |
28 ============================================================================
29 Generic Server Setup Starting - Stage 1
30 ============================================================================
31 Target Host: {{ inventory_hostname }}
32 Target IP: {{ ansible_default_ipv4.address | default('Unknown') }}
33 OS: {{ ansible_distribution | default('Unknown') }} {{ ansible_distribution_version | default('') }}
34 Architecture: {{ ansible_architecture | default('Unknown') }}
35 Server Type: {{ server_type | default('Unknown') }}
36 Node Type: {{ 'Kitchen' if inventory_hostname == 'hifi-node-kitchen' else 'Dining' }}
37 ============================================================================
38 tags: always
39
40 - name: Update apt cache
41 apt:
42 update_cache: yes
43 cache_valid_time: 3600
44 when: ansible_os_family == "Debian"
45
46 # ============================================================================
47 # GENERIC SERVER SETUP (System + User + Docker)
48 # ============================================================================
49
50 roles:
51 # System configuration (hostname, packages, sudo, etc.)
52 - role: system
53 tags: [system, base, configuration]
54
55 # Docker installation via geerlingguy.docker
56 - role: geerlingguy.docker
57 tags: [docker, containers]
58
59 # Security hardening via geerlingguy.security
60 - role: geerlingguy.security
61 tags: [security, hardening]
62
63 # System monitoring
64 - role: monitoring
65 tags: [monitoring, glances]
66
67 tasks:
68 - name: Configure user with proper group memberships
69 include_role:
70 name: user
71 vars:
72 my_user_username: yannick
73 my_user_groups: "{{ user_groups | default(['docker', 'sudo']) }}"
74 my_user_ssh_public_key: "{{ user_ssh_keys[0] | default('') if user_ssh_keys is defined and user_ssh_keys|length > 0 else '' }}"
75 tags: [user, setup, configuration]
76
77 # ============================================================================
78 # POST-INSTALLATION VALIDATION
79 # ============================================================================
80
81 post_tasks:
82 - name: System validation
83 block:
84 - name: Check hostname
85 command: "hostname"
86 register: hostname_check
87 changed_when: false
88
89 - name: Check Docker installation
90 command: "docker --version"
91 register: docker_check
92 failed_when: false
93 changed_when: false
94
95 - name: Check Docker service status
96 systemd:
97 name: docker
98 register: docker_service
99 ignore_errors: yes
100
101 - name: Check SSH configuration
102 command: "sshd -t"
103 register: ssh_config_check
104 changed_when: false
105
106 - name: Check user in docker group
107 command: "groups yannick"
108 register: user_groups_check
109 changed_when: false
110
111 tags: [validation, system, snapcast]
112
113 - name: Display configuration summary
114 debug:
115 msg: |
116 ============================================================================
117 Generic Server Setup Complete! - Stage 1 Finished
118 ============================================================================
119
120 ð¥ï¸ System Information:
121 Hostname: {{ hostname_check.stdout | default('Unknown') }}
122 Target Host: {{ inventory_hostname }}
123 IP Address: {{ ansible_default_ipv4.address | default('Unknown') }}
124 OS: {{ ansible_distribution | default('Unknown') }} {{ ansible_distribution_version | default('') }}
125 Architecture: {{ ansible_architecture | default('Unknown') }}
126 Server Type: {{ server_type | default('Unknown') }}
127
128 ð³ Docker Configuration:
129 Docker Version: {{ docker_check.stdout | default('Not installed') }}
130 Docker Service: {{ 'Running' if docker_service is defined and docker_service.status.ActiveState == 'active' else 'Not running' }}
131 Docker Users: yannick
132
133 ð Security Configuration:
134 SSH Port: {{ security_ssh_port | default(22) }}
135 Password Auth: {{ security_ssh_password_authentication | default('yes') }}
136 Root Login: {{ security_ssh_permit_root_login | default('yes') }}
137 SSH Config: {{ 'â Valid' if ssh_config_check.rc == 0 else 'â Invalid' }}
138
139 ð¥ User Configuration:
140 Primary User: yannick
141 User Groups: {{ user_groups_check.stdout | default('Unknown') }}
142 Sudo Access: {{ 'Passwordless' if security_sudoers_passwordless is defined else 'Standard' }}
143
144 ð§ Validation Results:
145 Hostname Set: {{ 'â Success' if hostname_check.rc == 0 else 'â Failed' }}
146 Docker Installed: {{ 'â Success' if docker_check.rc == 0 else 'â Failed' }}
147 Docker Running: {{ 'â Running' if docker_service is defined and docker_service.status.ActiveState == 'active' else 'â Not running' }}
148 SSH Config Valid: {{ 'â Valid' if ssh_config_check.rc == 0 else 'â Invalid' }}
149
150 ð¡ Usage Examples:
151 SSH Login: ssh yannick@{{ ansible_default_ipv4.address | default(inventory_hostname) }}
152 Docker Commands: docker ps
153 System Status: systemctl status docker
154
155 ð Next Steps:
156 1. Test SSH access with your private key
157 2. Verify Docker functionality: docker run hello-world
158 3. Deploy additional services as needed
159
160 ============================================================================
161 tags: [always, snapcast]
162
163# STAGE 2: Snapcast client configuration with individual parameters
164- name: "Snapcast Client Configuration - Individual Node Setup"
165 hosts: hifi_nodes
166 become: true
167 gather_facts: false # No need to gather facts again
168
169 pre_tasks:
170 - name: Display snapcast configuration information
171 debug:
172 msg: |
173 ============================================================================
174 Snapcast Client Configuration - Stage 2
175 ============================================================================
176 Target Host: {{ inventory_hostname }}
177 Node Type: {{ 'Kitchen (mono mixing)' if inventory_hostname == 'hifi-node-kitchen' else 'Dining (stereo)' }}
178 Audio Device: {{ 'hw:1,0' if inventory_hostname == 'hifi-node-kitchen' else 'hw:0,0' }}
179 Mono Mixing: {{ 'Enabled' if inventory_hostname == 'hifi-node-kitchen' else 'Disabled' }}
180 Snapcast Server: {{ hostvars[groups['homeassistant_servers'][0]].ansible_host | default('homeassistant.home') }}
181 ============================================================================
182 tags: always
183
184 roles:
185 - role: snapcast-client
186 tags: [snapcast, audio, hifi]
187 vars:
188 # Configure based on node type
189 audio_merge_to_mono: "{{ inventory_hostname == 'hifi-node-kitchen' }}"
190 manage_asound_conf: "{{ inventory_hostname == 'hifi-node-kitchen' }}"
191
192 # Device configuration
193 audio_hw_device: "{{ 'hw:1,0' if inventory_hostname == 'hifi-node-kitchen' else 'hw:0,0' }}"
194 audio_ctl_card: "{{ 1 if inventory_hostname == 'hifi-node-kitchen' else 0 }}"
195 snapcast_device: "{{ 'hw:0,0' if inventory_hostname == 'hifi-node-dining' }}"
196
197 # Server configuration using inventory lookup
198 snapcast_server_host: "{{ hostvars[groups['homeassistant_servers'][0]].ansible_host | default('homeassistant.home') }}"
199 snapcast_client_name: "{{ inventory_hostname }}"
200
201 # Disable Avahi for explicit server configuration
202 enable_avahi: false
203
204 post_tasks:
205 - name: Validate snapcast installation
206 block:
207 - name: Check snapclient service status
208 systemd:
209 name: snapclient
210 register: snapclient_service
211
212 - name: Check snapclient configuration
213 command: "cat /etc/default/snapclient"
214 register: snapclient_config
215 changed_when: false
216
217 tags: [validation, snapcast]
218
219 - name: Display snapcast configuration summary
220 debug:
221 msg: |
222 ============================================================================
223 Snapcast Client Configuration Complete! - Stage 2 Finished
224 ============================================================================
225
226 ð Snapcast Configuration:
227 Client Name: {{ inventory_hostname }}
228 Server Host: {{ hostvars[groups['homeassistant_servers'][0]].ansible_host | default('homeassistant.home') }}
229 Audio Device: {{ 'hw:1,0 (mono mixed)' if inventory_hostname == 'hifi-node-kitchen' else 'hw:0,0 (stereo)' }}
230 Service Status: {{ 'Running' if snapclient_service.status.ActiveState == 'active' else 'Not running' }}
231
232 ð§ Validation Results:
233 Snapcast Running: {{ 'â Running' if snapclient_service.status.ActiveState == 'active' else 'â Not running' }}
234
235 ð¡ Usage Examples:
236 Snapcast Status: systemctl status snapclient
237 Snapcast Logs: journalctl -u snapclient -f
238
239 ð Next Steps:
240 1. Test audio playback from HomeAssistant server
241 2. Verify mono mixing on kitchen node (if applicable)
242 3. Check sync between multiple clients
243
244 ============================================================================
245 tags: [always, snapcast]