/
/
/
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 tasks:
64 - name: Configure user with proper group memberships
65 include_role:
66 name: user
67 vars:
68 my_user_username: yannick
69 my_user_groups: "{{ user_groups | default(['docker', 'sudo']) }}"
70 my_user_ssh_public_key: "{{ user_ssh_keys[0] | default('') if user_ssh_keys is defined and user_ssh_keys|length > 0 else '' }}"
71 tags: [user, setup, configuration]
72
73 # ============================================================================
74 # POST-INSTALLATION VALIDATION
75 # ============================================================================
76
77 post_tasks:
78 - name: System validation
79 block:
80 - name: Check hostname
81 command: "hostname"
82 register: hostname_check
83 changed_when: false
84
85 - name: Check Docker installation
86 command: "docker --version"
87 register: docker_check
88 failed_when: false
89 changed_when: false
90
91 - name: Check Docker service status
92 systemd:
93 name: docker
94 register: docker_service
95 ignore_errors: yes
96
97 - name: Check SSH configuration
98 command: "sshd -t"
99 register: ssh_config_check
100 changed_when: false
101
102 - name: Check user in docker group
103 command: "groups yannick"
104 register: user_groups_check
105 changed_when: false
106
107 tags: [validation, system, snapcast]
108
109 - name: Display configuration summary
110 debug:
111 msg: |
112 ============================================================================
113 Generic Server Setup Complete! - Stage 1 Finished
114 ============================================================================
115
116 ð¥ï¸ System Information:
117 Hostname: {{ hostname_check.stdout | default('Unknown') }}
118 Target Host: {{ inventory_hostname }}
119 IP Address: {{ ansible_default_ipv4.address | default('Unknown') }}
120 OS: {{ ansible_distribution | default('Unknown') }} {{ ansible_distribution_version | default('') }}
121 Architecture: {{ ansible_architecture | default('Unknown') }}
122 Server Type: {{ server_type | default('Unknown') }}
123
124 ð³ Docker Configuration:
125 Docker Version: {{ docker_check.stdout | default('Not installed') }}
126 Docker Service: {{ 'Running' if docker_service is defined and docker_service.status.ActiveState == 'active' else 'Not running' }}
127 Docker Users: yannick
128
129 ð Security Configuration:
130 SSH Port: {{ security_ssh_port | default(22) }}
131 Password Auth: {{ security_ssh_password_authentication | default('yes') }}
132 Root Login: {{ security_ssh_permit_root_login | default('yes') }}
133 SSH Config: {{ 'â Valid' if ssh_config_check.rc == 0 else 'â Invalid' }}
134
135 ð¥ User Configuration:
136 Primary User: yannick
137 User Groups: {{ user_groups_check.stdout | default('Unknown') }}
138 Sudo Access: {{ 'Passwordless' if security_sudoers_passwordless is defined else 'Standard' }}
139
140 ð§ Validation Results:
141 Hostname Set: {{ 'â Success' if hostname_check.rc == 0 else 'â Failed' }}
142 Docker Installed: {{ 'â Success' if docker_check.rc == 0 else 'â Failed' }}
143 Docker Running: {{ 'â Running' if docker_service is defined and docker_service.status.ActiveState == 'active' else 'â Not running' }}
144 SSH Config Valid: {{ 'â Valid' if ssh_config_check.rc == 0 else 'â Invalid' }}
145
146 ð¡ Usage Examples:
147 SSH Login: ssh yannick@{{ ansible_default_ipv4.address | default(inventory_hostname) }}
148 Docker Commands: docker ps
149 System Status: systemctl status docker
150
151 ð Next Steps:
152 1. Test SSH access with your private key
153 2. Verify Docker functionality: docker run hello-world
154 3. Deploy additional services as needed
155
156 ============================================================================
157 tags: [always, snapcast]
158
159# STAGE 2: Snapcast client configuration with individual parameters
160- name: "Snapcast Client Configuration - Individual Node Setup"
161 hosts: hifi_nodes
162 become: true
163 gather_facts: false # No need to gather facts again
164
165 pre_tasks:
166 - name: Display snapcast configuration information
167 debug:
168 msg: |
169 ============================================================================
170 Snapcast Client Configuration - Stage 2
171 ============================================================================
172 Target Host: {{ inventory_hostname }}
173 Node Type: {{ 'Kitchen (mono mixing)' if inventory_hostname == 'hifi-node-kitchen' else 'Dining (stereo)' }}
174 Audio Device: {{ 'hw:1,0' if inventory_hostname == 'hifi-node-kitchen' else 'hw:0,0' }}
175 Mono Mixing: {{ 'Enabled' if inventory_hostname == 'hifi-node-kitchen' else 'Disabled' }}
176 Snapcast Server: {{ hostvars[groups['homeassistant_servers'][0]].ansible_host | default('homeassistant.home') }}
177 ============================================================================
178 tags: always
179
180 roles:
181 - role: snapcast-client
182 tags: [snapcast, audio, hifi]
183 vars:
184 # Configure based on node type
185 audio_merge_to_mono: "{{ inventory_hostname == 'hifi-node-kitchen' }}"
186 manage_asound_conf: "{{ inventory_hostname == 'hifi-node-kitchen' }}"
187
188 # Device configuration
189 audio_hw_device: "{{ 'hw:1,0' if inventory_hostname == 'hifi-node-kitchen' else 'hw:0,0' }}"
190 audio_ctl_card: "{{ 1 if inventory_hostname == 'hifi-node-kitchen' else 0 }}"
191 snapcast_device: "{{ 'hw:0,0' if inventory_hostname == 'hifi-node-dining' }}"
192
193 # Server configuration using inventory lookup
194 snapcast_server_host: "{{ hostvars[groups['homeassistant_servers'][0]].ansible_host | default('homeassistant.home') }}"
195 snapcast_client_name: "{{ inventory_hostname }}"
196
197 # Disable Avahi for explicit server configuration
198 enable_avahi: false
199
200 post_tasks:
201 - name: Validate snapcast installation
202 block:
203 - name: Check snapclient service status
204 systemd:
205 name: snapclient
206 register: snapclient_service
207
208 - name: Check snapclient configuration
209 command: "cat /etc/default/snapclient"
210 register: snapclient_config
211 changed_when: false
212
213 tags: [validation, snapcast]
214
215 - name: Display snapcast configuration summary
216 debug:
217 msg: |
218 ============================================================================
219 Snapcast Client Configuration Complete! - Stage 2 Finished
220 ============================================================================
221
222 ð Snapcast Configuration:
223 Client Name: {{ inventory_hostname }}
224 Server Host: {{ hostvars[groups['homeassistant_servers'][0]].ansible_host | default('homeassistant.home') }}
225 Audio Device: {{ 'hw:1,0 (mono mixed)' if inventory_hostname == 'hifi-node-kitchen' else 'hw:0,0 (stereo)' }}
226 Service Status: {{ 'Running' if snapclient_service.status.ActiveState == 'active' else 'Not running' }}
227
228 ð§ Validation Results:
229 Snapcast Running: {{ 'â Running' if snapclient_service.status.ActiveState == 'active' else 'â Not running' }}
230
231 ð¡ Usage Examples:
232 Snapcast Status: systemctl status snapclient
233 Snapcast Logs: journalctl -u snapclient -f
234
235 ð Next Steps:
236 1. Test audio playback from HomeAssistant server
237 2. Verify mono mixing on kitchen node (if applicable)
238 3. Check sync between multiple clients
239
240 ============================================================================
241 tags: [always, snapcast]