diff --git a/plays/emma.yml b/plays/emma.yml index a708cc5..bc1d00d 100644 --- a/plays/emma.yml +++ b/plays/emma.yml @@ -60,3 +60,18 @@ webdav_user: "{{ vault_webdav_user }}" webdav_password: "{{ vault_webdav_password }}" webdav_password_bcrypt: "{{ vault_webdav_password_bcrypt }}" + +- name: Set up Otter + hosts: emma + become: yes + tags: otter + roles: + - role: any.common.btrfs-subvolumes + vars: + subvolumes: + - filesystem_uuid: "{{ btrfs_nvme.uuid }}" + filesystem_path: "{{ btrfs_nvme.path }}" + name: "/@rootfs/otter/data" + - role: any.software.otter + vars: + data_dir: '{{ btrfs_nvme.path }}/data/otter/data' diff --git a/roles/any.software.otter/files/otter.Caddyfile b/roles/any.software.otter/files/otter.Caddyfile new file mode 100644 index 0000000..9ea78b0 --- /dev/null +++ b/roles/any.software.otter/files/otter.Caddyfile @@ -0,0 +1,3 @@ +otter.roosens.me { + reverse_proxy localhost:8017 +} diff --git a/roles/any.software.otter/files/otter.data.backup.sh b/roles/any.software.otter/files/otter.data.backup.sh new file mode 100644 index 0000000..dc63b24 --- /dev/null +++ b/roles/any.software.otter/files/otter.data.backup.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +data_dir='/mnt/data1/otter/data' +snapshot_dir="${data_dir}.snapshot" + +# Read-only snapshot for atomic backup +btrfs subvolume snapshot -r "$data_dir" "$snapshot_dir" || exit $? + +/usr/local/bin/restic backup "$snapshot_dir" + +# Always remove snapshot subvolume, even if restic fails +btrfs subvolume delete "$snapshot_dir" diff --git a/roles/any.software.otter/files/otter.service b/roles/any.software.otter/files/otter.service new file mode 100644 index 0000000..97e93dc --- /dev/null +++ b/roles/any.software.otter/files/otter.service @@ -0,0 +1,13 @@ +[Unit] +Description=Gpodder.net API implementation +After=network.target network-online.target + +[Service] +Type=exec +User=otter +Group=otter +ExecStart=/usr/local/bin/otter serve -c /etc/otter/otter.toml +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/roles/any.software.otter/handlers/main.yml b/roles/any.software.otter/handlers/main.yml new file mode 100644 index 0000000..c4bf72e --- /dev/null +++ b/roles/any.software.otter/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: 'restart otter' + ansible.builtin.service: + name: 'otter' + state: 'restarted' diff --git a/roles/any.software.otter/meta/main.yml b/roles/any.software.otter/meta/main.yml new file mode 100644 index 0000000..d620a12 --- /dev/null +++ b/roles/any.software.otter/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: any.tools.caddy diff --git a/roles/any.software.otter/tasks/main.yml b/roles/any.software.otter/tasks/main.yml new file mode 100644 index 0000000..ae71b52 --- /dev/null +++ b/roles/any.software.otter/tasks/main.yml @@ -0,0 +1,85 @@ +--- +- name: Ensure binary is present + ansible.builtin.get_url: + url: 'https://git.rustybever.be/api/packages/Chewing_Bever/generic/otter/0.3.0/otter-linux-amd64' + dest: '/usr/local/bin/otter' + owner: 'root' + group: 'root' + mode: '755' + notify: 'restart otter' + +- name: Ensure system group exists + ansible.builtin.group: + name: 'otter' + gid: 204 + system: true + state: present + +- name: Ensure system user exists + ansible.builtin.user: + name: 'otter' + group: 'otter' + uid: 204 + system: true + create_home: false + +- name: Ensure permissions are correct + ansible.builtin.file: + path: "{{ data_dir }}" + state: directory + mode: '0755' + owner: '204' + group: '204' + +- name: Ensure configuration directory is present + ansible.builtin.file: + path: '/etc/otter' + state: directory + mode: '0755' + +- name: Ensure config file is present + ansible.builtin.template: + src: 'otter.toml.j2' + dest: '/etc/otter/otter.toml' + mode: '0644' + owner: 'root' + group: 'root' + notify: 'restart otter' + +- name: Ensure Caddyfile is present + ansible.builtin.copy: + src: 'otter.Caddyfile' + dest: '/etc/caddy/otter.Caddyfile' + owner: root + group: root + mode: '0644' + notify: reload caddy + +# - name: Ensure backup scripts are present +# ansible.builtin.copy: +# src: "otter.{{ item }}.backup.sh" +# dest: "/etc/backups/otter.{{ item }}.backup.sh" +# owner: 'root' +# group: 'root' +# mode: '0644' +# loop: +# - 'data' + +- name: Ensure service file is present + ansible.builtin.copy: + src: 'otter.service' + dest: '/lib/systemd/system/otter.service' + owner: 'root' + group: 'root' + mode: '0644' + register: res + +- name: systemd-reload + ansible.builtin.systemd_service: + daemon_reload: true + when: 'res.changed' + +- name: Ensure otter service is enabled + ansible.builtin.service: + name: 'otter' + enabled: true diff --git a/roles/any.software.otter/templates/otter.toml.j2 b/roles/any.software.otter/templates/otter.toml.j2 new file mode 100644 index 0000000..0affcac --- /dev/null +++ b/roles/any.software.otter/templates/otter.toml.j2 @@ -0,0 +1,7 @@ +data_dir = "{{ data_dir }}" +log_level = "debug" + +[net] +type = "tcp" +domain = "0.0.0.0" +port = 8017