/
/
/
This repo is destined for my server automations and setup.
1---
2# ============================================================================
3# Audio Client Deployment Playbook
4# ============================================================================
5#
6# This playbook deploys audio clients to HiFi nodes in two stages:
7# 1. Generic server setup on all hifi-nodes (system, docker, security, user)
8# 2. Audio client configuration with individual parameters per node
9#
10# Supports Snapcast and Sendspin backends via audio_client_type variable.
11#
12# Usage:
13# ansible-playbook hifi-nodes.yml
14#
15# ============================================================================
16
17# STAGE 1: Generic server setup on all hifi-nodes
18- name: "Generic Server Setup - HiFi Nodes Group"
19 hosts: hifi_nodes
20 become: true
21 gather_facts: true
22
23 # Load configuration from group_vars and host_vars
24 # Override with command line variables as needed
25
26 pre_tasks:
27 - name: Display deployment information
28 debug:
29 msg: |
30 ============================================================================
31 Generic Server Setup Starting - Stage 1
32 ============================================================================
33 Target Host: {{ inventory_hostname }}
34 Target IP: {{ ansible_default_ipv4.address | default('Unknown') }}
35 OS: {{ ansible_distribution | default('Unknown') }} {{ ansible_distribution_version | default('') }}
36 Architecture: {{ ansible_architecture | default('Unknown') }}
37 Server Type: {{ server_type | default('Unknown') }}
38 Node Type: {{ 'Kitchen' if inventory_hostname == 'hifi-node-kitchen' else 'Dining' }}
39 ============================================================================
40 tags: always
41
42 - name: Update apt cache
43 apt:
44 update_cache: yes
45 cache_valid_time: 3600
46 when: ansible_os_family == "Debian"
47
48 # ============================================================================
49 # GENERIC SERVER SETUP (System + User + Docker)
50 # ============================================================================
51
52 roles:
53 # System configuration (hostname, packages, sudo, etc.)
54 - role: system
55 tags: [system, base, configuration]
56
57 # Docker installation via geerlingguy.docker
58 - role: geerlingguy.docker
59 tags: [docker, containers]
60
61 # Docker directory framework (proper /docker permissions)
62 - role: docker-framework
63 tags: [docker, framework]
64
65 # Security hardening via geerlingguy.security
66 - role: geerlingguy.security
67 tags: [security, hardening]
68
69 # System monitoring
70 - role: monitoring
71 tags: [monitoring, glances]
72
73 tasks:
74 - name: Configure user with proper group memberships
75 include_role:
76 name: user
77 vars:
78 my_user_username: yannick
79 my_user_groups: "{{ user_groups | default(['docker', 'sudo']) }}"
80 my_user_ssh_public_key: "{{ user_ssh_keys[0] | default('') if user_ssh_keys is defined and user_ssh_keys|length > 0 else '' }}"
81 tags: [user, setup, configuration]
82
83 # ============================================================================
84 # POST-INSTALLATION VALIDATION
85 # ============================================================================
86
87 post_tasks:
88 - name: System validation
89 block:
90 - name: Check hostname
91 command: "hostname"
92 register: hostname_check
93 changed_when: false
94
95 - name: Check Docker installation
96 command: "docker --version"
97 register: docker_check
98 failed_when: false
99 changed_when: false
100
101 - name: Check Docker service status
102 systemd:
103 name: docker
104 register: docker_service
105 ignore_errors: yes
106
107 - name: Check SSH configuration
108 command: "sshd -t"
109 register: ssh_config_check
110 changed_when: false
111
112 - name: Check user in docker group
113 command: "groups yannick"
114 register: user_groups_check
115 changed_when: false
116
117 tags: [validation, system]
118
119 - name: Display configuration summary
120 debug:
121 msg: |
122 ============================================================================
123 Generic Server Setup Complete! - Stage 1 Finished
124 ============================================================================
125
126 System Information:
127 Hostname: {{ hostname_check.stdout | default('Unknown') }}
128 Target Host: {{ inventory_hostname }}
129 IP Address: {{ ansible_default_ipv4.address | default('Unknown') }}
130 OS: {{ ansible_distribution | default('Unknown') }} {{ ansible_distribution_version | default('') }}
131 Architecture: {{ ansible_architecture | default('Unknown') }}
132 Server Type: {{ server_type | default('Unknown') }}
133
134 Docker Configuration:
135 Docker Version: {{ docker_check.stdout | default('Not installed') }}
136 Docker Service: {{ 'Running' if docker_service is defined and docker_service.status.ActiveState == 'active' else 'Not running' }}
137 Docker Users: yannick
138
139 Security Configuration:
140 SSH Port: {{ security_ssh_port | default(22) }}
141 Password Auth: {{ security_ssh_password_authentication | default('yes') }}
142 Root Login: {{ security_ssh_permit_root_login | default('yes') }}
143 SSH Config: {{ 'Valid' if ssh_config_check is defined and ssh_config_check.rc == 0 else 'Skipped' if ssh_config_check is not defined else 'Invalid' }}
144
145 User Configuration:
146 Primary User: yannick
147 User Groups: {{ user_groups_check.stdout | default('Skipped') }}
148 Sudo Access: {{ 'Passwordless' if security_sudoers_passwordless is defined else 'Standard' }}
149
150 Validation Results:
151 Hostname Set: {{ 'OK' if hostname_check is defined and hostname_check.rc == 0 else 'Skipped' if hostname_check is not defined else 'Failed' }}
152 Docker Installed: {{ 'OK' if docker_check is defined and docker_check.rc == 0 else 'Skipped' if docker_check is not defined else 'Failed' }}
153 Docker Running: {{ 'OK' if docker_service is defined and docker_service.status.ActiveState == 'active' else 'Skipped' if docker_service is not defined else 'Not running' }}
154 SSH Config Valid: {{ 'OK' if ssh_config_check is defined and ssh_config_check.rc == 0 else 'Skipped' if ssh_config_check is not defined else 'Invalid' }}
155
156 ============================================================================
157 tags: [always]
158
159# STAGE 2: Audio client configuration with individual parameters
160- name: "Audio 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 audio client configuration information
167 debug:
168 msg: |
169 ============================================================================
170 Audio Client Configuration - Stage 2
171 ============================================================================
172 Target Host: {{ inventory_hostname }}
173 Audio Backend: {{ audio_client_type | default('snapcast') }}
174 Node Type: {{ 'Kitchen (mono mixing)' if inventory_hostname == 'hifi-node-kitchen' else 'Dining (stereo)' }}
175 Audio Device: {{ 'hw:1,0' if inventory_hostname == 'hifi-node-kitchen' else 'hw:0,0' }}
176 Mono Mixing: {{ 'Enabled' if inventory_hostname == 'hifi-node-kitchen' else 'Disabled' }}
177 ============================================================================
178 tags: always
179
180 roles:
181 - role: audio-client
182 tags: [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: "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 audio client installation
202 block:
203 - name: Check snapclient service status
204 systemd:
205 name: snapclient
206 register: snapclient_service
207 when: audio_client_type | default('snapcast') == "snapcast"
208 ignore_errors: true
209
210 - name: Check sendspin service status
211 systemd:
212 name: sendspin
213 register: sendspin_service
214 when: audio_client_type | default('snapcast') == "sendspin"
215 ignore_errors: true
216
217 tags: [validation, audio]
218
219 - name: Display audio client configuration summary
220 debug:
221 msg: |
222 ============================================================================
223 Audio Client Configuration Complete! - Stage 2 Finished
224 ============================================================================
225
226 Audio Configuration:
227 Client Name: {{ inventory_hostname }}
228 Backend: {{ audio_client_type | default('snapcast') }}
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 is defined and snapclient_service.status is defined and snapclient_service.status.ActiveState == 'active') or (sendspin_service is defined and sendspin_service.status is defined and sendspin_service.status.ActiveState == 'active') else 'Not running / Skipped' }}
231
232 ============================================================================
233 tags: [always]
234