--- # The user, the directories, and the binary. - name: Install Navidrome's runtime dependencies apt: name: # Navidrome shells out to ffmpeg for on-the-fly transcoding. Without it # the server starts fine and every format the client cannot play natively # simply fails, which looks like a client bug. - ffmpeg - curl state: present update_cache: true - name: Create the navidrome system group group: name: "{{ navidrome_group }}" system: yes state: present - name: Create the navidrome system user user: name: "{{ navidrome_user }}" group: "{{ navidrome_group }}" system: yes shell: /usr/sbin/nologin home: "{{ navidrome_data_dir }}" create_home: no comment: "Navidrome Music Server" state: present - name: Create the navidrome data directory ansible.builtin.file: path: "{{ navidrome_data_dir }}" state: directory owner: "{{ navidrome_user }}" group: "{{ navidrome_group }}" mode: '0750' - name: Create the navidrome config directory ansible.builtin.file: path: "{{ navidrome_config_dir }}" state: directory owner: root group: "{{ navidrome_group }}" mode: '0750' # Two principals share this tree and neither is root: the curator writes it # through beets, Navidrome only reads it. setgid (the 2) is load-bearing - # without it, files beets creates land in the curator's own group and Navidrome # cannot read them, which presents as an empty library rather than an error. - name: Create the music library directory ansible.builtin.file: path: "{{ navidrome_music_dir }}" state: directory owner: "{{ navidrome_curator_user }}" group: "{{ navidrome_group }}" mode: '2750' - name: Create the incoming staging directory ansible.builtin.file: path: "{{ navidrome_incoming_dir }}" state: directory owner: "{{ navidrome_curator_user }}" group: "{{ navidrome_curator_user }}" mode: '0755' # check_mode: no on the next two - this repo verifies with `--check --diff`, so # the role has to survive a dry run. A read-only version probe and a temp # directory are both harmless to perform for real, and without them every task # below evaluates against an undefined navidrome_tmp.path and the check aborts. - name: Check the installed navidrome version ansible.builtin.command: "{{ navidrome_bin_path }} --version" register: navidrome_installed_version changed_when: false failed_when: false check_mode: no - name: Decide whether navidrome needs installing ansible.builtin.set_fact: navidrome_needs_install: "{{ navidrome_version not in (navidrome_installed_version.stdout | default('')) }}" - name: Create a temporary directory for the navidrome download ansible.builtin.tempfile: state: directory suffix: navidrome register: navidrome_tmp when: navidrome_needs_install | bool check_mode: no # checksum: is the verification. Upstream publishes navidrome_checksums.txt per # release but signs nothing, so there is no signature to check the way # roles/monero checks binaryfate's - this pins the exact artefact and no more. - name: Download the navidrome release tarball ansible.builtin.get_url: url: "{{ navidrome_url }}" dest: "{{ navidrome_tmp.path }}/navidrome.tar.gz" checksum: "sha256:{{ navidrome_sha256 }}" mode: '0644' when: navidrome_needs_install | bool and not ansible_check_mode - name: Unpack the navidrome tarball ansible.builtin.unarchive: src: "{{ navidrome_tmp.path }}/navidrome.tar.gz" dest: "{{ navidrome_tmp.path }}" remote_src: yes when: navidrome_needs_install | bool and not ansible_check_mode - name: Install the navidrome binary ansible.builtin.copy: src: "{{ navidrome_tmp.path }}/navidrome" dest: "{{ navidrome_bin_path }}" remote_src: yes owner: root group: root mode: '0755' when: navidrome_needs_install | bool and not ansible_check_mode notify: Restart navidrome - name: Remove the navidrome download directory ansible.builtin.file: path: "{{ navidrome_tmp.path }}" state: absent when: navidrome_needs_install | bool check_mode: no # Check mode skips the three tasks above, so without this a dry run is silent # about the single most important thing it would do. - name: Report what a real run would install ansible.builtin.debug: msg: >- Would install navidrome {{ navidrome_version }} to {{ navidrome_bin_path }} (currently: {{ navidrome_installed_version.stdout | default('not installed') | trim }}) when: navidrome_needs_install | bool and ansible_check_mode