Files
ansible/roles/pi_musicmouse/tasks/main.yml
Martin Bauer edca1e47dc Stop the delegated frontend build from sudoing on the control machine
pi_standard_setup's defaults set `ansible_become: true`. Role defaults are
play-wide host variables, and in Ansible's precedence the `ansible_become`
variable outranks the `become` keyword - so the `become: false` on every
pi_musicmouse task delegated to localhost was silently overridden and each one
tried to sudo on the machine running ansible:

    Premature end of stream waiting for become success or become password prompt

Those defaults earn their keep bootstrapping a fresh Pi, where you connect as
`pi` and become root to enable root login, so override the variable on the
delegated tasks rather than removing them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 20:46:07 +02:00

161 lines
5.7 KiB
YAML

---
- name: Packages
ansible.builtin.apt:
name:
- git
- libvlc5 # runtime lib python-vlc (installed into the venv by uv) binds against
- vlc-plugin-base
- alsa-utils
- samba
cache_valid_time: 7200
- name: Ensure uv install directory exists
ansible.builtin.file:
path: "/opt/uv-{{ pi_musicmouse_uv_version }}-{{ pi_musicmouse_uv_target }}"
state: directory
mode: "0755"
- name: Download and extract uv {{ pi_musicmouse_uv_version }}
ansible.builtin.unarchive:
src: "https://github.com/astral-sh/uv/releases/download/{{ pi_musicmouse_uv_version }}/uv-{{ pi_musicmouse_uv_target }}.tar.gz"
dest: "/opt/uv-{{ pi_musicmouse_uv_version }}-{{ pi_musicmouse_uv_target }}"
remote_src: true
extra_opts: ["--strip-components=1"]
creates: "/opt/uv-{{ pi_musicmouse_uv_version }}-{{ pi_musicmouse_uv_target }}/uv"
- name: Symlink uv/uvx into /usr/local/bin
ansible.builtin.file:
src: "/opt/uv-{{ pi_musicmouse_uv_version }}-{{ pi_musicmouse_uv_target }}/{{ item }}"
dest: "/usr/local/bin/{{ item }}"
state: link
force: true
loop:
- uv
- uvx
- name: Verify uv runs on this host
ansible.builtin.command:
cmd: /usr/local/bin/uv --version
register: pi_musicmouse_uv_version_out
changed_when: false
- name: Checkout Musicmouse repo
ansible.builtin.git:
repo: "{{ pi_musicmouse_repo }}"
dest: /opt/musicmouse
version: "{{ musicmouse_version }}"
accept_hostkey: true
force: true
notify: Reinstall musicmouse backend
- name: Check the checkout has the layout this role knows
ansible.builtin.stat:
path: /opt/musicmouse/python-backend/pyproject.toml
register: pi_musicmouse_pyproject
# Meaningless under --check on a host that has never been deployed: the git task
# above reports "changed" without writing anything, so there is nothing to stat.
when: not ansible_check_mode
- name: Fail on a pre-rearchitecture checkout
ansible.builtin.fail:
msg: >-
{{ musicmouse_version }} has no python-backend/pyproject.toml, so it predates the
rearchitecture and this role cannot install it - the venv, the systemd unit and
the web/ build all live somewhere else on those commits. Point
musicmouse_version at a branch that has it (deploy/musicdolphin), or set
mediapi_install_kidsmusic to false for this host and leave whatever is installed
alone. Stopping here rather than failing three tasks deeper with the real reason
buried.
when: not ansible_check_mode and not pi_musicmouse_pyproject.stat.exists
- name: Create virtualenv with Python {{ pi_musicmouse_python_version }}
ansible.builtin.command:
cmd: "/usr/local/bin/uv venv --python {{ pi_musicmouse_python_version }} /opt/musicmouse/.venv"
creates: /opt/musicmouse/.venv/bin/python
- name: Create media directory
ansible.builtin.file:
path: /media/musicmouse
state: directory
mode: "0755"
- name: Install config file
ansible.builtin.copy:
src: "{{ pi_musicmouse_config_file }}"
dest: /media/musicmouse/config.yml
mode: "0644"
# Install-once: the app writes this file itself (parent mode's volume keys, the
# remote-control mapping). See pi_musicmouse_force_config in defaults.
force: "{{ pi_musicmouse_force_config }}"
notify: Restart musicmouse
- name: Install tippen curriculum
ansible.builtin.copy:
src: "{{ pi_musicmouse_curriculum_file }}"
dest: /media/musicmouse/tippen-curriculum.yml
mode: "0644"
when: pi_musicmouse_curriculum_file | length > 0
notify: Restart musicmouse
- name: Install systemd service file (from the checked-out repo, not a copy kept here)
ansible.builtin.copy:
src: /opt/musicmouse/python-backend/musicmouse.service
dest: /etc/systemd/system/musicmouse.service
mode: "0644"
remote_src: true
notify: Restart musicmouse
- name: Add script to autostart and start now
ansible.builtin.systemd:
name: musicmouse
state: started
enabled: "yes"
daemon_reload: "yes"
- name: Ensure local frontend build cache directory exists
ansible.builtin.file:
path: "{{ pi_musicmouse_build_cache }}/{{ musicmouse_version | regex_replace('/', '_') }}"
state: directory
mode: "0755"
delegate_to: localhost
become: false
vars:
# `become: false` above is not enough on its own. pi_standard_setup's defaults set
# `ansible_become: true`, role defaults are play-wide host variables, and the
# `ansible_become` *variable* outranks the `become` *keyword* in Ansible's
# precedence - so every task here tried to sudo on the control machine. Those
# defaults are needed to bootstrap a fresh Pi (connect as `pi`, become root, enable
# root login), so override the variable here rather than removing them.
ansible_become: false
- name: Checkout Musicmouse repo for frontend build (control machine)
ansible.builtin.git:
repo: "{{ pi_musicmouse_repo }}"
dest: "{{ pi_musicmouse_build_cache }}/{{ musicmouse_version | regex_replace('/', '_') }}"
version: "{{ musicmouse_version }}"
accept_hostkey: true
force: true
delegate_to: localhost
become: false
vars:
ansible_become: false # see the first delegated task in tasks/main.yml
notify: Build frontend
- name: Samba setup
ansible.builtin.copy:
src: smb.conf
dest: /etc/samba/
mode: "0644"
- name: Restart samba
ansible.builtin.systemd:
name: smbd
state: restarted
enabled: "yes"
daemon_reload: "yes"
# manual steps:
# - set samba passwords with smbpasswd
# - copy music into /media/musicmouse: scripts/sync-library.sh in the app repo, which
# also carries the cover and analysis cache over (or use the samba share, and let
# the device spend the DSP time itself)