From 6d38e1dc5cf23e878615478a3b78a0a55becce66344cd2cd86e3dae07cf03eac Mon Sep 17 00:00:00 2001 From: bryan Date: Thu, 29 Jan 2026 23:34:14 -0500 Subject: [PATCH] Refactor to reduce config in group_vars --- roles/quadlets/README.md => README.md | 0 group_vars/all/{software.yml => apps.yml} | 33 +- group_vars/all/dotfiles.yml | 20 - group_vars/all/filesystems.yml | 20 + group_vars/all/services.yml | 16 - group_vars/laptop/btrbk.yml | 18 + group_vars/laptop/dotfiles.yml | 19 - group_vars/laptop/services.yml | 3 - group_vars/laptop/software.yml | 7 - group_vars/workstation/btrbk.yml | 34 ++ group_vars/workstation/dotfiles.yml | 19 - group_vars/workstation/quadlets.yml | 2 - group_vars/workstation/services.yml | 3 - group_vars/workstation/software.yml | 3 - playbook.yml | 18 +- roles/apps/aichat.yml | 13 + roles/apps/btrbk.yml | 124 +++++ roles/apps/btrfsmaintenance.yml | 162 ++++++ roles/apps/code.yml | 5 + roles/apps/dnf-automatic.yml | 2 + roles/apps/dnf.yml | 11 + roles/apps/keyd.yml | 14 + roles/apps/mediacenter35.yml | 5 + roles/apps/mullvad-vpn.yml | 3 + roles/apps/profile-sync-daemon.yml | 2 + roles/apps/pwrstatd.yml | 140 +++++ roles/apps/tailscale.yml | 2 + roles/{software => apps}/tasks/main.yml | 54 +- roles/apps/zsh-completions.yml | 5 + roles/dotfiles/README.md | 43 ++ roles/dotfiles/{home => }/env/.env.j2 | 0 roles/dotfiles/{home => }/git/.gitconfig | 0 .../home/aichat/.config/aichat/config.yaml.j2 | 7 - .../home/btrbk-ws/.config/btrbk/btrbk.conf | 253 --------- .../home/btrbk/.config/btrbk/btrbk.conf | 176 ------ .../.local/share/nautilus/scripts/share-link | 0 roles/dotfiles/root/dnf/etc/dnf/dnf.conf | 8 - .../dotfiles/root/keyd/etc/keyd/default.conf | 5 - .../dotfiles/root/pwrstatd/etc/pwrstatd.conf | 131 ----- .../sysconfig/etc/sysconfig/btrfsmaintenance | 154 ----- .../{home => }/ssh/.ssh/authorized_keys.j2 | 0 roles/dotfiles/{home => }/ssh/.ssh/config | 0 roles/dotfiles/tasks/main.yml | 61 +- roles/dotfiles/{home => }/tmux/.tmux.conf | 0 roles/dotfiles/{home => }/vim/.vimrc | 0 .../{home => }/x2go/.x2goclient/sessions | 0 roles/dotfiles/{home => }/zsh/.zshrc | 0 roles/filesystems/tasks/main.yml | 8 + roles/quadlets/lazylibrarian.yml | 145 +++++ roles/quadlets/lazylibrarian/config.ini.j2 | 129 ----- roles/quadlets/lazylibrarian/quadlets.yml | 11 - roles/quadlets/lidarr.yml | 49 ++ roles/quadlets/lidarr/quadlets.yml | 48 -- roles/quadlets/prowlarr.yml | 47 ++ roles/quadlets/prowlarr/quadlets.yml | 44 -- roles/quadlets/qbittorrent.yml | 162 ++++++ .../qBittorrent/config/qBittorrent.conf.j2 | 127 ----- roles/quadlets/qbittorrent/quadlets.yml | 30 - roles/quadlets/radarr.yml | 46 ++ roles/quadlets/radarr/quadlets.yml | 46 -- roles/quadlets/sabnzbd.yml | 524 ++++++++++++++++++ roles/quadlets/sabnzbd/quadlets.yml | 42 -- roles/quadlets/sabnzbd/sabnzbd.ini.j2 | 477 ---------------- roles/quadlets/sonarr.yml | 44 ++ roles/quadlets/sonarr/quadlets.yml | 43 -- roles/quadlets/tasks/main.yml | 29 +- roles/quadlets/traefik.yml | 73 +++ roles/quadlets/traefik/dynamic/htpc.yml.j2 | 116 ---- roles/quadlets/traefik/quadlets.yml | 19 - roles/quadlets/traefik/server.crt.j2 | 1 - roles/quadlets/traefik/server.key.j2 | 1 - roles/quadlets/unpackerr.yml | 37 ++ roles/quadlets/unpackerr/quadlets.yml | 36 -- roles/scripts/tasks/main.yml | 36 +- roles/scripts/tmux-management | 20 +- roles/services/tasks/main.yml | 34 -- 76 files changed, 1900 insertions(+), 2119 deletions(-) rename roles/quadlets/README.md => README.md (100%) rename group_vars/all/{software.yml => apps.yml} (60%) delete mode 100644 group_vars/all/dotfiles.yml delete mode 100644 group_vars/all/services.yml create mode 100644 group_vars/laptop/btrbk.yml delete mode 100644 group_vars/laptop/dotfiles.yml delete mode 100644 group_vars/laptop/services.yml delete mode 100644 group_vars/laptop/software.yml create mode 100644 group_vars/workstation/btrbk.yml delete mode 100644 group_vars/workstation/dotfiles.yml delete mode 100644 group_vars/workstation/services.yml delete mode 100644 group_vars/workstation/software.yml create mode 100644 roles/apps/aichat.yml create mode 100644 roles/apps/btrbk.yml create mode 100644 roles/apps/btrfsmaintenance.yml create mode 100644 roles/apps/code.yml create mode 100644 roles/apps/dnf-automatic.yml create mode 100644 roles/apps/dnf.yml create mode 100644 roles/apps/keyd.yml create mode 100644 roles/apps/mediacenter35.yml create mode 100644 roles/apps/mullvad-vpn.yml create mode 100644 roles/apps/profile-sync-daemon.yml create mode 100644 roles/apps/pwrstatd.yml create mode 100644 roles/apps/tailscale.yml rename roles/{software => apps}/tasks/main.yml (52%) create mode 100644 roles/apps/zsh-completions.yml create mode 100644 roles/dotfiles/README.md rename roles/dotfiles/{home => }/env/.env.j2 (100%) rename roles/dotfiles/{home => }/git/.gitconfig (100%) delete mode 100644 roles/dotfiles/home/aichat/.config/aichat/config.yaml.j2 delete mode 100644 roles/dotfiles/home/btrbk-ws/.config/btrbk/btrbk.conf delete mode 100644 roles/dotfiles/home/btrbk/.config/btrbk/btrbk.conf rename roles/dotfiles/{home => }/nautilus/.local/share/nautilus/scripts/share-link (100%) delete mode 100644 roles/dotfiles/root/dnf/etc/dnf/dnf.conf delete mode 100644 roles/dotfiles/root/keyd/etc/keyd/default.conf delete mode 100644 roles/dotfiles/root/pwrstatd/etc/pwrstatd.conf delete mode 100644 roles/dotfiles/root/sysconfig/etc/sysconfig/btrfsmaintenance rename roles/dotfiles/{home => }/ssh/.ssh/authorized_keys.j2 (100%) rename roles/dotfiles/{home => }/ssh/.ssh/config (100%) rename roles/dotfiles/{home => }/tmux/.tmux.conf (100%) rename roles/dotfiles/{home => }/vim/.vimrc (100%) rename roles/dotfiles/{home => }/x2go/.x2goclient/sessions (100%) rename roles/dotfiles/{home => }/zsh/.zshrc (100%) create mode 100644 roles/quadlets/lazylibrarian.yml delete mode 100644 roles/quadlets/lazylibrarian/config.ini.j2 delete mode 100644 roles/quadlets/lazylibrarian/quadlets.yml create mode 100644 roles/quadlets/lidarr.yml delete mode 100644 roles/quadlets/lidarr/quadlets.yml create mode 100644 roles/quadlets/prowlarr.yml delete mode 100644 roles/quadlets/prowlarr/quadlets.yml create mode 100644 roles/quadlets/qbittorrent.yml delete mode 100644 roles/quadlets/qbittorrent/qBittorrent/config/qBittorrent.conf.j2 delete mode 100644 roles/quadlets/qbittorrent/quadlets.yml create mode 100644 roles/quadlets/radarr.yml delete mode 100644 roles/quadlets/radarr/quadlets.yml create mode 100644 roles/quadlets/sabnzbd.yml delete mode 100644 roles/quadlets/sabnzbd/quadlets.yml delete mode 100644 roles/quadlets/sabnzbd/sabnzbd.ini.j2 create mode 100644 roles/quadlets/sonarr.yml delete mode 100644 roles/quadlets/sonarr/quadlets.yml create mode 100644 roles/quadlets/traefik.yml delete mode 100644 roles/quadlets/traefik/dynamic/htpc.yml.j2 delete mode 100644 roles/quadlets/traefik/quadlets.yml delete mode 100644 roles/quadlets/traefik/server.crt.j2 delete mode 100644 roles/quadlets/traefik/server.key.j2 create mode 100644 roles/quadlets/unpackerr.yml delete mode 100644 roles/quadlets/unpackerr/quadlets.yml delete mode 100644 roles/services/tasks/main.yml diff --git a/roles/quadlets/README.md b/README.md similarity index 100% rename from roles/quadlets/README.md rename to README.md diff --git a/group_vars/all/software.yml b/group_vars/all/apps.yml similarity index 60% rename from group_vars/all/software.yml rename to group_vars/all/apps.yml index 852ada4..c78f6e7 100644 --- a/group_vars/all/software.yml +++ b/group_vars/all/apps.yml @@ -1,22 +1,4 @@ --- -dnf_add_repos: - - name: zsh-completions - description: zsh-completions from openSUSE - baseurl: https://download.opensuse.org/repositories/shells:zsh-users:zsh-completions/Fedora_Rawhide/ - gpgkey: https://download.opensuse.org/repositories/shells:zsh-users:zsh-completions/Fedora_Rawhide/repodata/repomd.xml.key - - name: code - description: Visual Studio Code - baseurl: https://packages.microsoft.com/yumrepos/vscode - gpgkey: https://packages.microsoft.com/keys/microsoft.asc - - name: jriver - description: JRiver Media Center by BryanC - baseurl: https://repos.bryanroessler.com/jriver - gpgcheck: false - -dnf_add_repofiles: - - name: Mullvad VPN - url: https://repository.mullvad.net/rpm/stable/mullvad.repo - dnf_remove_repos: - google-chrome @@ -29,7 +11,12 @@ dnf_remove: - orca - rhythmbox -dnf_install: +services_system_disabled: + - qemu-guest-agent + - raid-check.timer + - fstrim.timer + +apps: - btrbk - btrfs-assistant - btrfsmaintenance @@ -37,6 +24,7 @@ dnf_install: - cargo - code - dnf-automatic + - firefox - flatpak - gettext - gnome-tweaks @@ -61,11 +49,6 @@ dnf_install: - zsh - zsh-completions -# Cargo packages to install -cargo_packages: - - aichat - -# Git repositories to clone git_add_repos: - repo: https://git.bryanroessler.com/bryan/installJRMC.git dest: "{{ ansible_facts['env']['HOME'] }}/.local/bin/installJRMC" @@ -79,3 +62,5 @@ git_add_repos: # - repo: https://git.bryanroessler.com/bryan/deploy.git # dest: "{{ ansible_facts['env']['HOME'] }}/.local/bin/deploy" # version: dev + + diff --git a/group_vars/all/dotfiles.yml b/group_vars/all/dotfiles.yml deleted file mode 100644 index 16443f0..0000000 --- a/group_vars/all/dotfiles.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -symlinks: - - name: develop - src: "{{ lookup('env', 'HOME') }}/documents/develop" - dest: "{{ lookup('env', 'HOME') }}/develop" - - name: music - src: "{{ lookup('env', 'HOME') }}/media/music" - dest: "{{ lookup('env', 'HOME') }}/music" - - name: pictures - src: "{{ lookup('env', 'HOME') }}/media/pictures" - dest: "{{ lookup('env', 'HOME') }}/pictures" - - name: videos - src: "{{ lookup('env', 'HOME') }}/media/videos" - dest: "{{ lookup('env', 'HOME') }}/videos" - - name: ebooks - src: "{{ lookup('env', 'HOME') }}/media/ebooks" - dest: "{{ lookup('env', 'HOME') }}/ebooks" - - name: bin - src: "{{ lookup('env', 'HOME') }}/.local/bin" - dest: "{{ lookup('env', 'HOME') }}/bin" diff --git a/group_vars/all/filesystems.yml b/group_vars/all/filesystems.yml index 4d25a4b..7de8b95 100644 --- a/group_vars/all/filesystems.yml +++ b/group_vars/all/filesystems.yml @@ -2,3 +2,23 @@ directories: - path: "{{ ansible_facts['env']['HOME'] }}/.local/bin" mode: '0755' + +symlinks: + - name: develop + src: "{{ lookup('env', 'HOME') }}/documents/develop" + dest: "{{ lookup('env', 'HOME') }}/develop" + - name: music + src: "{{ lookup('env', 'HOME') }}/media/music" + dest: "{{ lookup('env', 'HOME') }}/music" + - name: pictures + src: "{{ lookup('env', 'HOME') }}/media/pictures" + dest: "{{ lookup('env', 'HOME') }}/pictures" + - name: videos + src: "{{ lookup('env', 'HOME') }}/media/videos" + dest: "{{ lookup('env', 'HOME') }}/videos" + - name: ebooks + src: "{{ lookup('env', 'HOME') }}/media/ebooks" + dest: "{{ lookup('env', 'HOME') }}/ebooks" + - name: bin + src: "{{ lookup('env', 'HOME') }}/.local/bin" + dest: "{{ lookup('env', 'HOME') }}/bin" \ No newline at end of file diff --git a/group_vars/all/services.yml b/group_vars/all/services.yml deleted file mode 100644 index 7f531d8..0000000 --- a/group_vars/all/services.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -services_system_enabled: - - dnf-automatic.timer - - btrfs-balance.timer - - btrfs-scrub.timer - - btrfs-trim.timer - - btrbk.timer - - tailscaled - -services_user_enabled: - - psd - -services_system_disabled: - - qemu-guest-agent - - raid-check.timer - - fstrim.timer diff --git a/group_vars/laptop/btrbk.yml b/group_vars/laptop/btrbk.yml new file mode 100644 index 0000000..dac9026 --- /dev/null +++ b/group_vars/laptop/btrbk.yml @@ -0,0 +1,18 @@ +btrbk_ssh_identity: /root/.ssh/id_ed25519 +btrbk_ssh_user: root +btrbk_config: | + snapshot_preserve_min 2d + snapshot_preserve 14d + target_preserve_min no + target_preserve 14d 10w *m + archive_preserve_min latest + archive_preserve 12m 10y + + subvolume / + target_preserve 14d 10w 6m + snapshot_dir /.snapshots + target ssh://workstation/mnt/backup/laptop/root + + volume /home + subvolume bryan + target ssh://workstation/mnt/backup/laptop/home \ No newline at end of file diff --git a/group_vars/laptop/dotfiles.yml b/group_vars/laptop/dotfiles.yml deleted file mode 100644 index 587ad08..0000000 --- a/group_vars/laptop/dotfiles.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -# Home dotfile packages to deploy -dotfiles_home_packages: - - aichat - - btrbk - - env - - git - - nautilus - - ssh - - tmux - - vim - - x2go - - zsh - -# Root dotfile packages to deploy -dotfiles_root_packages: - - dnf - - sysconfig - - keyd diff --git a/group_vars/laptop/services.yml b/group_vars/laptop/services.yml deleted file mode 100644 index b88971f..0000000 --- a/group_vars/laptop/services.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -services_system_enabled_group: - - keyd diff --git a/group_vars/laptop/software.yml b/group_vars/laptop/software.yml deleted file mode 100644 index 182af17..0000000 --- a/group_vars/laptop/software.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- - -dnf_add_copr_group: - - alternateved/keyd - -dnf_install_group: - - keyd diff --git a/group_vars/workstation/btrbk.yml b/group_vars/workstation/btrbk.yml new file mode 100644 index 0000000..2d1f3aa --- /dev/null +++ b/group_vars/workstation/btrbk.yml @@ -0,0 +1,34 @@ +btrbk_ssh_identity: /home/bryan/.config/btrbk/id_ed25519 +btrbk_ssh_user: root +btrbk_config: | + snapshot_preserve_min 2d + snapshot_preserve 14d + target_preserve_min no + target_preserve 14d 10w *m + archive_preserve_min latest + archive_preserve 12m 10y + + subvolume / + target_preserve 14d 10w 6m + snapshot_dir /.snapshots + target /mnt/backup/workstation/root + + volume /home + subvolume bryan + target /mnt/backup/workstation/home + target_preserve 14d 10w 6m + + volume /mnt/downloads + subvolume downloads + target /mnt/backup/workstation/downloads + + volume / + subvolume /mnt/ebooks + target /mnt/backup/media + subvolume /mnt/cover-art + target /mnt/backup/media + + volume /mnt/array/media + target /mnt/backup/media + subvolume pictures + subvolume mu \ No newline at end of file diff --git a/group_vars/workstation/dotfiles.yml b/group_vars/workstation/dotfiles.yml deleted file mode 100644 index 2c640de..0000000 --- a/group_vars/workstation/dotfiles.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -# Home dotfile packages to deploy -dotfiles_home_packages: - - aichat - - btrbk-ws - - env - - git - - nautilus - - ssh - - tmux - - vim - - x2go - - zsh - -# Root dotfile packages to deploy -dotfiles_root_packages: - - dnf - - sysconfig - - pwrstatd diff --git a/group_vars/workstation/quadlets.yml b/group_vars/workstation/quadlets.yml index 4597193..ca4f35f 100644 --- a/group_vars/workstation/quadlets.yml +++ b/group_vars/workstation/quadlets.yml @@ -1,7 +1,5 @@ --- -debug: false # set to true to print debug info -log_level: "info" quadlets_deploy_configs: true # deploy quadlet service configs maintainer: "Bryan C. Roessler" diff --git a/group_vars/workstation/services.yml b/group_vars/workstation/services.yml deleted file mode 100644 index d83639a..0000000 --- a/group_vars/workstation/services.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -services_system_group: - - pwrstatd diff --git a/group_vars/workstation/software.yml b/group_vars/workstation/software.yml deleted file mode 100644 index 8142de4..0000000 --- a/group_vars/workstation/software.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -dnf_install_group: - - "https://dl4jz3rbrsfum.cloudfront.net/software/PPL_64bit_v1.4.1.rpm" diff --git a/playbook.yml b/playbook.yml index 8dd1247..026acfb 100644 --- a/playbook.yml +++ b/playbook.yml @@ -23,26 +23,20 @@ - role: dotfiles tags: ['dotfiles'] -- name: Deploy software +- name: Deploy sysconfig hosts: all roles: - - role: software - tags: ['software'] + - role: sysconfig + tags: ['sysconfig'] -- name: Deploy services +- name: Deploy apps hosts: all roles: - - role: services - tags: ['services'] + - role: apps + tags: ['apps'] - name: Deploy quadlets hosts: all roles: - role: quadlets tags: ['quadlets'] - -- name: Deploy sysconfig - hosts: all - roles: - - role: sysconfig - tags: ['sysconfig'] diff --git a/roles/apps/aichat.yml b/roles/apps/aichat.yml new file mode 100644 index 0000000..57d32f6 --- /dev/null +++ b/roles/apps/aichat.yml @@ -0,0 +1,13 @@ +cargo_packages_app: + - aichat + +configs: + - path: "{{ ansible_facts['env']['HOME'] }}/.config/aichat/config.yaml" + template: | + # see https://github.com/sigoden/aichat/blob/main/config.example.yaml + + model: claude:claude-haiku-4-5-20251001 + + clients: + - type: claude + api_key: {{ ANTHROPIC_API_KEY }} diff --git a/roles/apps/btrbk.yml b/roles/apps/btrbk.yml new file mode 100644 index 0000000..0215b53 --- /dev/null +++ b/roles/apps/btrbk.yml @@ -0,0 +1,124 @@ +services: + - btrbk.timer + +configs: + - path: /etc/btrbk/btrbk.conf + template: | + # + # Example btrbk configuration file + # + # + # Please refer to the btrbk.conf(5) man-page for a complete + # description of all configuration options. + # For more examples, see README.md included with this package. + # + # btrbk.conf(5): + # README.md: + # + # Note that the options can be overridden per volume/subvolume/target + # in the corresponding sections. + # + + + # Enable transaction log + transaction_log /var/log/btrbk.log + + # Specify SSH private key for remote connections + ssh_identity {{ btrbk_ssh_identity | default('/root/.ssh/id_ed25519') }} + ssh_user {{ btrbk_ssh_user | default('root') }} + + # Use sudo if btrbk or lsbtr is run by regular user + backend_local_user btrfs-progs-sudo + + # Enable stream buffer. Adding a buffer between the sending and + # receiving side is generally a good idea. + # NOTE: If enabled, make sure to install the "mbuffer" package! + stream_buffer 256m + + # Directory in which the btrfs snapshots are created. Relative to + # of the volume section. + # If not set, the snapshots are created in . + # + # If you want to set a custom name for the snapshot (and backups), + # use the "snapshot_name" option within the subvolume section. + # + # NOTE: btrbk does not autmatically create this directory, and the + # snapshot creation will fail if it is not present. + # + snapshot_dir .snapshots + + # Always create snapshots. Set this to "ondemand" to only create + # snapshots if the target volume is reachable. Set this to "no" if + # snapshot creation is done by another instance of btrbk. + snapshot_create onchange + + # Perform incremental backups (set to "strict" if you want to prevent + # creation of non-incremental backups if no parent is found). + #incremental yes + + # Specify after what time (in full hours after midnight) backups/ + # snapshots are considered as a daily backup/snapshot + #preserve_hour_of_day 0 + + # Specify on which day of week weekly/monthly backups are to be + # preserved. + #preserve_day_of_week sunday + + # Preserve all snapshots for a minimum period of time. + #snapshot_preserve_min 1d + + # Retention policy for the source snapshots. + #snapshot_preserve h d w m y + + # Preserve all backup targets for a minimum period of time. + #target_preserve_min no + + # Retention policy for backup targets: + #target_preserve h d w m y + + # Retention policy for archives ("btrbk archive" command): + #archive_preserve_min no + #archive_preserve h d w m y + + # Enable compression for remote btrfs send/receive operations: + #stream_compress no + #stream_compress_level default + #stream_compress_threads default + + # Enable lock file support: Ensures that only one instance of btrbk + # can be run at a time. + lockfile /var/lock/btrbk.lock + + # Don't wait for transaction commit on deletion. Set this to "after" + # or "each" to make sure the deletion of subvolumes is committed to + # disk when btrbk terminates. + #btrfs_commit_delete no + + + # + # Volume section (optional): "volume " + # + # Base path within a btrfs filesystem + # containing the subvolumes to be backuped + # (usually the mount-point of a btrfs filesystem + # mounted with subvolid=5 option). + # + # Subvolume section: "subvolume " + # + # Subvolume to be backuped, relative to + # in volume section. + # + # Target section: "target " + # + # (optional) type, defaults to "send-receive". + # Directory within a btrfs filesystem + # receiving the backups. + # + # NOTE: The parser does not care about indentation, this is only for + # human readability. All options apply to the last section + # encountered, overriding the corresponding option of the upper + # section. This means that the global options must be set on top, + # before any "volume", "subvolume" or "target section. + # + + {{ btrbk_config }} \ No newline at end of file diff --git a/roles/apps/btrfsmaintenance.yml b/roles/apps/btrfsmaintenance.yml new file mode 100644 index 0000000..1312dda --- /dev/null +++ b/roles/apps/btrfsmaintenance.yml @@ -0,0 +1,162 @@ +services: + - btrfs-balance.timer + - btrfs-scrub.timer + - btrfs-trim.timer + +configs: + - path: /etc/sysconfig/btrfsmaintenance + template: | + ## Path: System/File systems/btrfs + ## Type: string(none,stdout,journal,syslog) + ## Default: "stdout" + # + # Output target for messages. Journal and syslog messages are tagged by the task name like + # 'btrfs-scrub' etc. + BTRFS_LOG_OUTPUT="journal" + + ## Path: System/File systems/btrfs + ## Type: string + ## Default: "" + # + # Run periodic defrag on selected paths. The files from a given path do not + # cross mount points or other subvolumes/snapshots. If you want to defragment + # nested subvolumes, all have to be listed in this variable. + # (Colon separated paths) + BTRFS_DEFRAG_PATHS="" + + ## Path: System/File systems/btrfs + ## Type: string(none,daily,weekly,monthly) + ## Default: "none" + ## ServiceRestart: btrfsmaintenance-refresh + # + # Frequency of defrag. + BTRFS_DEFRAG_PERIOD="none" + + ## Path: System/File systems/btrfs + ## Type: string + ## Default: "+1M" + # + # Minimal file size to consider for defragmentation + BTRFS_DEFRAG_MIN_SIZE="+1M" + + ## Path: System/File systems/btrfs + ## Type: string + ## Default: "/" + # + # Which mountpoints/filesystems to balance periodically. This may reclaim unused + # portions of the filesystem and make the rest more compact. + # (Colon separated paths) + # The special word/mountpoint "auto" will evaluate all mounted btrfs + # filesystems + BTRFS_BALANCE_MOUNTPOINTS="auto" + + ## Path: System/File systems/btrfs + ## Type: string(none,daily,weekly,monthly) + ## Default: "weekly" + ## ServiceRestart: btrfsmaintenance-refresh + # + # Frequency of periodic balance. + # + # The frequency may be specified using one of the listed values or + # in the format documented in the "Calendar Events" section of systemd.time(7), + # if available. + BTRFS_BALANCE_PERIOD="weekly" + + ## Path: System/File systems/btrfs + ## Type: string + ## Default: "5 10" + # + # The usage percent for balancing data block groups. + # + # Note: default values should not disturb normal work but may not reclaim + # enough block groups. If you observe that, add higher values but beware that + # this will increase IO load on the system. + BTRFS_BALANCE_DUSAGE="0 20 50 80" + + ## Path: System/File systems/btrfs + ## Type: string + ## Default: "5" + # + # The usage percent for balancing metadata block groups. The values are also + # used in case the filesystem has mixed blockgroups. + # + # Note: default values should not disturb normal work but may not reclaim + # enough block groups. If you observe that, add higher values but beware that + # this will increase IO load on the system. + BTRFS_BALANCE_MUSAGE="80" + + ## Path: System/File systems/btrfs + ## Type: string + ## Default: "/" + # + # Which mountpoints/filesystems to scrub periodically. + # (Colon separated paths) + # The special word/mountpoint "auto" will evaluate all mounted btrfs + # filesystems + BTRFS_SCRUB_MOUNTPOINTS="auto" + + ## Path: System/File systems/btrfs + ## Type: string(none,weekly,monthly) + ## Default: "monthly" + ## ServiceRestart: btrfsmaintenance-refresh + # + # Frequency of periodic scrub. + # + # The frequency may be specified using one of the listed values or + # in the format documented in the "Calendar Events" section of systemd.time(7), + # if available. + BTRFS_SCRUB_PERIOD="quarterly" + + ## Path: System/File systems/btrfs + ## Type: string(idle,normal) + ## Default: "idle" + # + # Priority of IO at which the scrub process will run. Idle should not degrade + # performance but may take longer to finish. + BTRFS_SCRUB_PRIORITY="idle" + + ## Path: System/File systems/btrfs + ## Type: boolean + ## Default: "false" + # + # Do read-only scrub and don't try to repair anything. + BTRFS_SCRUB_READ_ONLY="false" + + ## Path: System/File systems/btrfs + ## Description: Configuration for periodic fstrim + ## Type: string(none,daily,weekly,monthly) + ## Default: "none" + ## ServiceRestart: btrfsmaintenance-refresh + # + # Frequency of periodic trim. Off by default so it does not collide with + # fstrim.timer . If you do not use the timer, turn it on here. The recommended + # period is 'weekly'. + # + # The frequency may be specified using one of the listed values or + # in the format documented in the "Calendar Events" section of systemd.time(7), + # if available. + BTRFS_TRIM_PERIOD="weekly" + + ## Path: System/File systems/btrfs + ## Description: Configuration for periodic fstrim - mountpoints + ## Type: string + ## Default: "/" + # + # Which mountpoints/filesystems to trim periodically. + # (Colon separated paths) + # The special word/mountpoint "auto" will evaluate all mounted btrfs + # filesystems + BTRFS_TRIM_MOUNTPOINTS="auto" + + ## Path: System/File systems/btrfs + ## Description: Configuration to allow concurrent jobs + ## Type: boolean + ## Default: "false" + # + # These maintenance tasks may compete for resources with each other, blocking + # out other tasks from using the file systems. This option will force + # these jobs to run in FIFO order when scheduled at overlapping times. This + # may include tasks scheduled to run when a system resumes or boots when + # the timer for these tasks(s) elapsed while the system was suspended + # or powered off. + BTRFS_ALLOW_CONCURRENCY="false" diff --git a/roles/apps/code.yml b/roles/apps/code.yml new file mode 100644 index 0000000..fa6adec --- /dev/null +++ b/roles/apps/code.yml @@ -0,0 +1,5 @@ +dnf_add_repos_app: + - name: code + description: Visual Studio Code + baseurl: https://packages.microsoft.com/yumrepos/vscode + gpgkey: https://packages.microsoft.com/keys/microsoft.asc \ No newline at end of file diff --git a/roles/apps/dnf-automatic.yml b/roles/apps/dnf-automatic.yml new file mode 100644 index 0000000..245a30b --- /dev/null +++ b/roles/apps/dnf-automatic.yml @@ -0,0 +1,2 @@ +services: + - dnf-automatic.timer \ No newline at end of file diff --git a/roles/apps/dnf.yml b/roles/apps/dnf.yml new file mode 100644 index 0000000..fd4e623 --- /dev/null +++ b/roles/apps/dnf.yml @@ -0,0 +1,11 @@ +configs: + path: /etc/dnf/dnf.conf + template: | + # see `man dnf.conf` for defaults and possible options + + [main] + # installonly_limit=3 + # best=False + skip_if_unavailable=True + deltarpm=True + fastestmirror=True diff --git a/roles/apps/keyd.yml b/roles/apps/keyd.yml new file mode 100644 index 0000000..f91170f --- /dev/null +++ b/roles/apps/keyd.yml @@ -0,0 +1,14 @@ +dnf_add_copr_app: + - alternateved/keyd + +services: + - keyd + +configs: + path: /etc/keyd/default.conf + template: | + [ids] + 0001:0001:09b4e68d + + [main] + leftmeta+leftshift+f23 = rightcontrol \ No newline at end of file diff --git a/roles/apps/mediacenter35.yml b/roles/apps/mediacenter35.yml new file mode 100644 index 0000000..22f4a6f --- /dev/null +++ b/roles/apps/mediacenter35.yml @@ -0,0 +1,5 @@ +dnf_add_repos_app: + - name: jriver + description: JRiver Media Center by BryanC + baseurl: https://repos.bryanroessler.com/jriver + gpgcheck: false \ No newline at end of file diff --git a/roles/apps/mullvad-vpn.yml b/roles/apps/mullvad-vpn.yml new file mode 100644 index 0000000..af6edf1 --- /dev/null +++ b/roles/apps/mullvad-vpn.yml @@ -0,0 +1,3 @@ +dnf_add_repofiles_app: + - name: Mullvad VPN + url: https://repository.mullvad.net/rpm/stable/mullvad.repo \ No newline at end of file diff --git a/roles/apps/profile-sync-daemon.yml b/roles/apps/profile-sync-daemon.yml new file mode 100644 index 0000000..dacb9c0 --- /dev/null +++ b/roles/apps/profile-sync-daemon.yml @@ -0,0 +1,2 @@ +services: + - psd.service \ No newline at end of file diff --git a/roles/apps/pwrstatd.yml b/roles/apps/pwrstatd.yml new file mode 100644 index 0000000..cb3e286 --- /dev/null +++ b/roles/apps/pwrstatd.yml @@ -0,0 +1,140 @@ +apps_app: + - "https://dl4jz3rbrsfum.cloudfront.net/software/PPL_64bit_v1.4.1.rpm" + +services: + - pwrstatd.service + +configs: + path: /etc/pwrstatd.conf + template: | + # + # pwrstatd configuration file + # + + # You must restart pwrstatd after changing this file in order for changes to take effect. + # Ex:/etc/init.d/pwrstatd restart + + # + # Action setting for event of Power Failure + # + + # A delay time in seconds since event of Power Failure occur then to run shell + # script and shutdown system. Allowed range is 0 ~ 3600. Default is 60 sec. + powerfail-delay = 60 + + # Enable to run shell script when the event of Power Failure occur. + # The allowed options are yes and no. Default is yes. + powerfail-active = no + + # Assign a path of script file for event of Power Failure. + # The default is /etc/pwrstatd-powerfail.sh + powerfail-cmd-path = /etc/pwrstatd-powerfail.sh + + # How much time in seconds to take script running for event of Power Failure. + # The allowed range is 0 ~ 3600. Default is 0 sec. + powerfail-duration = 0 + + # Allow Daemon to shutdown system for event of Power Failure. + # The allowed options are yes and no. Default is yes. + powerfail-shutdown = no + + # + # Action setting for event of Battery Low + # + + # A threshold of Battery Capacity, If the battery capacity is lower than this + # value and a event of Battery Low will be identified. The unit is percentage. + # The allowed range is 0 ~ 90. Default is 35 %. + lowbatt-threshold = 10 + + # A threshold of Remaining Runtime, If the Remaining Runtime is lower than this + # value and a event of Battery Low will be identified. The unit is second. + # The allowed range is 0 ~ 3600. Default is 300 sec. + # Note: When meet this condition the below 'shutdown-sustain' property + # will be ignored. + runtime-threshold = 180 + + # Enable to run shell script when the event of Battery Low occur. + # The allowed options are yes and no. Default is yes. + lowbatt-active = no + + # Assign a path of script file for event of Battery Low. + # The default is /etc/pwrstatd-lowbatt.sh + lowbatt-cmd-path = /etc/pwrstatd-lowbatt.sh + + # How much time in seconds to take script running for event of Battery Low. + # The allowed range is 0 ~ 60. Default is 0 sec. + lowbatt-duration = 0 + + # Allow Daemon to shutdown system for event of Battery Low. + # The allowed options are yes and no. Default is yes. + lowbatt-shutdown = yes + + # Turn UPS alarm on or off. + # The allowed options are yes and no. Default is yes. + enable-alarm = yes + + # The necessary time in seconds for system shutdown. + # The UPS will turn power off when this time is expired. + # The allowed range is 0 ~ 3600. Default is 600 sec.(10 min.) + # If the computer shutdown is cause by low runtime condition, the UPS will + # turn power off when the time is expired that time is assigned on + # 'runtime-threshold' property and it is no longer to refer the + # 'shutdown-sustain' property. + shutdown-sustain = 0 + + # Daemon will turn UPS power off once it ask system shutdown cause by a power + # event. Allowed options are yes and no. Default is yes. + turn-ups-off = no + + # The period of polling UPS in seconds. + # The allowed range is 1 ~ 60. Default is 3 sec. + ups-polling-rate = 5 + + # the period of re-try to find available UPS in seconds since find nothing at + # last time. The allowed range is 1 ~ 300. Default is 10 sec. + ups-retry-rate = 10 + + # Prohibiting daemon to provide communication mechanism for client, such as + # pwrstat command. normally, it should be 'no'. It can be 'yes' if any security + # consideration. Allowed options are yes and no. Default is no. + prohibit-client-access = no + + # The pwrstatd accepts four types of device node which includes the 'ttyS', + # 'ttyUSB', 'hiddev', and 'libusb' for communication with UPS. The pwrstatd + # defaults to enumerate all acceptable device nodes and pick up to use an + # available device node automatically. But this may cause a disturbance to the + # device node which is occupied by other software. Therefore, you can restrict + # this enumerate behave by using allowed-device-nodes option. You can assign + # the single device node path or multiple device node paths divided by a + # semicolon at this option. All groups of 'ttyS', 'ttyUSB', 'hiddev', or + # 'libusb' device node are enumerated without a suffix number assignment. + # Note, the 'libusb' does not support suffix number only. + # + # For example: restrict to use ttyS1, ttyS2 and hiddev1 device nodes at /dev + # path only. + # allowed-device-nodes = /dev/ttyS1;/dev/ttyS2;/dev/hiddev1 + # + # For example: restrict to use ttyS and ttyUSB two groups of device node at + # /dev,/dev/usb, and /dev/usb/hid paths(includes ttyS0 to ttySN and ttyUSB0 to + # ttyUSBN, N is number). + # allowed-device-nodes = ttyS;ttyUSB + # + # For example: restrict to use hiddev group of device node at /dev,/dev/usb, + # and /dev/usb/hid paths(includes hiddev0 to hiddevN, N is number). + # allowed-device-nodes = hiddev + # + # For example: restrict to use libusb device. + # allowed-device-nodes = libusb + allowed-device-nodes = + + # Daemon will hibernate system to instead of system shutdown when power + # event occur. Allowed options are yes and no. Default is no. + hibernate = no + + # Enable cloud solution. + # The allowed options are yes and no. Default is no. + cloud-active = no + + # Account for cloud server login. + cloud-account = \ No newline at end of file diff --git a/roles/apps/tailscale.yml b/roles/apps/tailscale.yml new file mode 100644 index 0000000..9807ad0 --- /dev/null +++ b/roles/apps/tailscale.yml @@ -0,0 +1,2 @@ +services: + - tailscaled.service \ No newline at end of file diff --git a/roles/software/tasks/main.yml b/roles/apps/tasks/main.yml similarity index 52% rename from roles/software/tasks/main.yml rename to roles/apps/tasks/main.yml index b3f959b..ba69861 100644 --- a/roles/software/tasks/main.yml +++ b/roles/apps/tasks/main.yml @@ -1,10 +1,9 @@ --- - - name: Enable COPR repositories community.general.copr: name: "{{ item.repo | default(item) }}" state: enabled - loop: "{{ (dnf_add_copr | default([])) + (dnf_add_copr_group | default([])) }}" + loop: "{{ (dnf_add_copr | default([])) + (dnf_add_copr_group | default([])) + (dnf_add_copr_app | default([])) }}" become: true - name: Add DNF repositories @@ -15,7 +14,7 @@ enabled: true gpgcheck: "{{ item.gpgcheck | default(true) }}" gpgkey: "{{ item.gpgkey | default(omit) }}" - loop: "{{ (dnf_add_repos | default([])) + (dnf_add_repos_group | default([])) }}" + loop: "{{ (dnf_add_repos | default([])) + (dnf_add_repos_group | default([])) + (dnf_add_repos_app | default([])) }}" become: true - name: Add DNF repository files @@ -25,7 +24,7 @@ owner: root group: root mode: '0644' - loop: "{{ (dnf_add_repofiles | default([])) + (dnf_add_repofiles_group | default([])) }}" + loop: "{{ (dnf_add_repofiles | default([])) + (dnf_add_repofiles_group | default([])) + (dnf_add_repofiles_app | default([])) }}" become: true - name: Remove DNF repositories @@ -46,11 +45,10 @@ - name: Install DNF packages ansible.builtin.dnf: - name: "{{ (dnf_install | default([])) + (dnf_install_group | default([])) }}" + name: "{{ (apps | default([])) + (apps_group | default([])) + (apps_app | default([])) }}" state: present skip_broken: true become: true - when: ((dnf_install | default([])) + (dnf_install_group | default([]))) | length > 0 - name: Update all DNF packages ansible.builtin.dnf: @@ -62,11 +60,11 @@ - name: Install cargo packages ansible.builtin.command: cmd: "cargo install {{ item }}" - loop: "{{ (cargo_packages | default([])) + (cargo_packages_group | default([])) }}" - when: ((cargo_packages | default([])) + (cargo_packages_group | default([]))) | length > 0 - register: software_cargo_install_result - changed_when: "'Installing' in software_cargo_install_result.stderr or 'Compiling' in software_cargo_install_result.stderr" - failed_when: software_cargo_install_result.rc != 0 and 'already exists' not in software_cargo_install_result.stderr + loop: "{{ (cargo_packages | default([])) + (cargo_packages_group | default([])) + (cargo_packages_app | default([])) }}" + when: ((cargo_packages | default([])) + (cargo_packages_group | default([])) + (cargo_packages_app | default([]))) | length > 0 + register: apps_cargo_install_result + changed_when: "'Installing' in apps_cargo_install_result.stderr or 'Compiling' in apps_cargo_install_result.stderr" + failed_when: apps_cargo_install_result.rc != 0 and 'already exists' not in apps_cargo_install_result.stderr - name: Clone git repositories ansible.builtin.git: @@ -75,3 +73,37 @@ version: "{{ item.version }}" update: true loop: "{{ (git_add_repos | default([])) + (git_add_repos_group | default([])) }}" + +- name: Enable and start system services + ansible.builtin.systemd: + name: "{{ item }}" + enabled: true + state: started + scope: system + loop: "{{ (services_system_enabled | default([])) + (services_system_enabled_group | default([])) + (services_system_enabled_app | default([])) }}" + become: true + +- name: Disable and stop system services + ansible.builtin.systemd: + name: "{{ item }}" + enabled: false + state: stopped + scope: system + loop: "{{ (services_system_disabled | default([])) + (services_system_disabled_group | default([])) + (services_system_disabled_app | default([])) }}" + become: true + +- name: Enable and start user services + ansible.builtin.systemd: + name: "{{ item }}" + enabled: true + state: started + scope: user + loop: "{{ (services_user_enabled | default([])) + (services_user_enabled_group | default([])) + (services_user_enabled_app | default([])) }}" + +- name: Disable and stop user services + ansible.builtin.systemd: + name: "{{ item }}" + enabled: false + state: stopped + scope: system + loop: "{{ (services_user_disabled | default([])) + (services_user_disabled_group | default([])) + (services_user_disabled_app | default([])) }}" \ No newline at end of file diff --git a/roles/apps/zsh-completions.yml b/roles/apps/zsh-completions.yml new file mode 100644 index 0000000..f66cb7e --- /dev/null +++ b/roles/apps/zsh-completions.yml @@ -0,0 +1,5 @@ +dnf_add_repos_app: + - name: zsh-completions + description: zsh-completions from openSUSE + baseurl: https://download.opensuse.org/repositories/shells:zsh-users:zsh-completions/Fedora_Rawhide/ + gpgkey: https://download.opensuse.org/repositories/shells:zsh-users:zsh-completions/Fedora_Rawhide/repodata/repomd.xml.key \ No newline at end of file diff --git a/roles/dotfiles/README.md b/roles/dotfiles/README.md new file mode 100644 index 0000000..226413f --- /dev/null +++ b/roles/dotfiles/README.md @@ -0,0 +1,43 @@ +# Dotfiles Deployment Guide + +Deploy dotfiles using [GNU Stow](https://www.gnu.org/software/stow/). + +Each subdirectory is a stow package corresponding to a set of related dotfiles. + +## Deploy Dotfiles + +Run Stow from within your dotfiles directory: + +```sh +cd ~/dotfiles +stow bash +stow vim +stow git +``` + +This will symlink the files into your `$HOME` directory. + +## Deploy All Dotfiles + +To deploy all dotfiles at once: + +```sh +stow * +``` + +## Updating Dotfiles + +1. Edit files in the respective subdirectories. +2. Commit and push changes as usual with Git. + +## Undoing a Stow + +To remove symlinks created by Stow: + +```sh +stow -D bash +``` + +--- + +For more details, see the [GNU Stow manual](https://www.gnu.org/software/stow/manual/stow.html). \ No newline at end of file diff --git a/roles/dotfiles/home/env/.env.j2 b/roles/dotfiles/env/.env.j2 similarity index 100% rename from roles/dotfiles/home/env/.env.j2 rename to roles/dotfiles/env/.env.j2 diff --git a/roles/dotfiles/home/git/.gitconfig b/roles/dotfiles/git/.gitconfig similarity index 100% rename from roles/dotfiles/home/git/.gitconfig rename to roles/dotfiles/git/.gitconfig diff --git a/roles/dotfiles/home/aichat/.config/aichat/config.yaml.j2 b/roles/dotfiles/home/aichat/.config/aichat/config.yaml.j2 deleted file mode 100644 index 9e97c8f..0000000 --- a/roles/dotfiles/home/aichat/.config/aichat/config.yaml.j2 +++ /dev/null @@ -1,7 +0,0 @@ -# see https://github.com/sigoden/aichat/blob/main/config.example.yaml - -model: claude:claude-haiku-4-5-20251001 - -clients: - - type: claude - api_key: {{ ANTHROPIC_API_KEY }} diff --git a/roles/dotfiles/home/btrbk-ws/.config/btrbk/btrbk.conf b/roles/dotfiles/home/btrbk-ws/.config/btrbk/btrbk.conf deleted file mode 100644 index eca11a2..0000000 --- a/roles/dotfiles/home/btrbk-ws/.config/btrbk/btrbk.conf +++ /dev/null @@ -1,253 +0,0 @@ -# -# Example btrbk configuration file -# -# -# Please refer to the btrbk.conf(5) man-page for a complete -# description of all configuration options. -# For more examples, see README.md included with this package. -# -# btrbk.conf(5): -# README.md: -# -# Note that the options can be overridden per volume/subvolume/target -# in the corresponding sections. -# - - -# Enable transaction log -transaction_log /var/log/btrbk.log - -# Specify SSH private key for remote connections -ssh_identity /home/bryan/.config/btrbk/id_ed25519 -ssh_user root - -# Use sudo if btrbk or lsbtr is run by regular user -backend_local_user btrfs-progs-sudo - -# Enable stream buffer. Adding a buffer between the sending and -# receiving side is generally a good idea. -# NOTE: If enabled, make sure to install the "mbuffer" package! -stream_buffer 1g - -# Directory in which the btrfs snapshots are created. Relative to -# of the volume section. -# If not set, the snapshots are created in . -# -# If you want to set a custom name for the snapshot (and backups), -# use the "snapshot_name" option within the subvolume section. -# -# NOTE: btrbk does not automatically create this directory, and the -# snapshot creation will fail if it is not present. -# -snapshot_dir .snapshots - -# Always create snapshots. Set this to "ondemand" to only create -# snapshots if the target volume is reachable. Set this to "no" if -# snapshot creation is done by another instance of btrbk. -snapshot_create onchange - -# Perform incremental backups (set to "strict" if you want to prevent -# creation of non-incremental backups if no parent is found). -#incremental yes - -# Specify after what time (in full hours after midnight) backups/ -# snapshots are considered as a daily backup/snapshot -#preserve_hour_of_day 0 - -# Specify on which day of week weekly/monthly backups are to be -# preserved. -#preserve_day_of_week sunday - -# Preserve all snapshots for a minimum period of time. -#snapshot_preserve_min 1d - -# Retention policy for the source snapshots. -#snapshot_preserve h d w m y - -# Preserve all backup targets for a minimum period of time. -#target_preserve_min no - -# Retention policy for backup targets: -#target_preserve h d w m y - -# Retention policy for archives ("btrbk archive" command): -#archive_preserve_min no -#archive_preserve h d w m y - -# Enable compression for remote btrfs send/receive operations: -#stream_compress no -#stream_compress_level default -#stream_compress_threads default - -# Enable lock file support: Ensures that only one instance of btrbk -# can be run at a time. -lockfile /var/lock/btrbk.lock - -# Don't wait for transaction commit on deletion. Enable this to make -# sure the deletion of subvolumes is committed to disk when btrbk -# terminates. -#btrfs_commit_delete no - - -# -# Volume section (optional): "volume " -# -# Base path within a btrfs filesystem -# containing the subvolumes to be backuped -# (usually the mount-point of a btrfs filesystem -# mounted with subvolid=5 option). -# -# Subvolume section: "subvolume " -# -# Subvolume to be backuped, relative to -# in volume section. -# -# Target section: "target " -# -# (optional) type, defaults to "send-receive". -# Directory within a btrfs filesystem -# receiving the backups. -# -# NOTE: The parser does not care about indentation, this is only for -# human readability. All options apply to the last section -# encountered, overriding the corresponding option of the upper -# section. This means that the global options must be set on top, -# before any "volume", "subvolume" or "target section. -# - -# -# Example retention policy: -# -# snapshot_preserve_min 2d -# snapshot_preserve 14d -# target_preserve_min no -# target_preserve 20d 10w *m - -snapshot_preserve_min 2d -snapshot_preserve 14d - -target_preserve_min no -target_preserve 14d 10w *m - -archive_preserve_min latest -archive_preserve 12m 10y - -# Global settings -compat_remote busybox -send_protocol 2 - -# Root backup workaround, omit the volume section -subvolume / - target_preserve 14d 10w 6m - snapshot_dir /.snapshots # Absolute path to snapshots dir - target /mnt/backup/workstation/root - # target ssh://router.lan/mnt/backup/workstation/root -# target /run/media/bryan/backup/workstation/root -# target ssh://home-router/mnt/backup/workstation/root - -volume /home - subvolume bryan - target /mnt/backup/workstation/home - # target ssh://router.lan/mnt/backup/workstation/home - target_preserve 14d 10w 6m - # target ssh://home-router/mnt/backup/workstation/home - # target /run/media/bryan/backup/workstation/home - -volume /mnt/downloads - subvolume downloads - target /mnt/backup/workstation/downloads - # target /run/media/bryan/backup/workstation/downloads - -volume / - subvolume /mnt/ebooks - target /mnt/backup/media - subvolume /mnt/cover-art - target /mnt/backup/media - # target ssh://router.lan/mnt/backup/media - # target ssh://home-router/mnt/backup/media - -volume /mnt/array/media - target /mnt/backup/media - # target ssh://router.lan/mnt/backup/media - # target ssh://home-router/mnt/backup/media - subvolume pictures - subvolume music - target_preserve_min all # for home-router to keep samba share (and safer overall) - - -# # -# # Simple setup: Backup root and home to external disk -# # -# snapshot_dir /btrbk_snapshots -# target /mnt/btr_backup -# subvolume / -# subvolume /home - - -# # -# # Complex setup -# # -# # In order to keep things organized, it is recommended to use "volume" -# # sections and mount the top-level subvolume (subvolid=5): -# # -# # $ mount -o subvolid=5 /dev/sda1 /mnt/btr_pool -# # -# # Backup to external disk mounted on /mnt/btr_backup -# volume /mnt/btr_pool -# # Create snapshots in /mnt/btr_pool/btrbk_snapshots -# snapshot_dir btrbk_snapshots - -# # Target for all subvolume sections: -# target /mnt/btr_backup - -# # Some default btrfs installations (e.g. Ubuntu) use "@" for rootfs -# # (mounted at "/") and "@home" (mounted at "/home"). Note that this -# # is only a naming convention. -# #subvolume @ -# subvolume root -# subvolume home -# subvolume kvm -# # Use different retention policy for kvm backups: -# target_preserve 7d 4w - - -# # Backup data to external disk as well as remote host -# volume /mnt/btr_data -# subvolume data -# # Always create snapshot, even if targets are unreachable -# snapshot_create always -# target /mnt/btr_backup -# target ssh://backup.my-remote-host.com/mnt/btr_backup - - -# # Backup from remote host, with different naming -# volume ssh://my-remote-host.com/mnt/btr_pool -# subvolume data_0 -# snapshot_dir snapshots/btrbk -# snapshot_name data_main -# target /mnt/btr_backup/my-remote-host.com - - -# # Backup on demand (noauto) to remote host running busybox, login as -# # regular user using ssh-agent with current user name (ssh_user no) -# # and default credentials (ssh_identity no). -# volume /home -# noauto yes -# compat busybox -# backend_remote btrfs-progs-sudo -# ssh_user no -# ssh_identity no - -# target ssh://my-user-host.com/mnt/btr_backup/home -# subvolume alice -# subvolume bob - - -# # Resume backups from remote host which runs its own btrbk instance -# # creating snapshots for "home" in "/mnt/btr_pool/btrbk_snapshots". -# volume ssh://my-remote-host.com/mnt/btr_pool -# snapshot_dir btrbk_snapshots -# snapshot_create no -# snapshot_preserve_min all -# subvolume home -# target /mnt/btr_backup/my-remote-host.com diff --git a/roles/dotfiles/home/btrbk/.config/btrbk/btrbk.conf b/roles/dotfiles/home/btrbk/.config/btrbk/btrbk.conf deleted file mode 100644 index 988b57f..0000000 --- a/roles/dotfiles/home/btrbk/.config/btrbk/btrbk.conf +++ /dev/null @@ -1,176 +0,0 @@ -# -# Example btrbk configuration file -# -# -# Please refer to the btrbk.conf(5) man-page for a complete -# description of all configuration options. -# -# Note that the options can be overridden per volume/subvolume/target -# in the corresponding sections. -# -# Enable transaction log -transaction_log /var/log/btrbk.log - -# Enable stream buffer. Adding a buffer between the sending and -# receiving side is generally a good idea. -# NOTE: If enabled, make sure the "mbuffer" package is installed on -# the target host! -#stream_buffer 512m - -# Directory in which the btrfs snapshots are created. Relative to -# of the volume section. -# If not set, the snapshots are created in . -# -# If you want to set a custom name for the snapshot (and backups), -# use the "snapshot_name" option within the subvolume section. -# -# NOTE: btrbk does not autmatically create this directory, and the -# snapshot creation will fail if it is not present. -# -snapshot_dir .snapshots - -# Always create snapshots. Set this to "ondemand" to only create -# snapshots if the target volume is reachable. Set this to "no" if -# snapshot creation is done by another instance of btrbk. -snapshot_create ondemand - -# Perform incremental backups (set to "strict" if you want to prevent -# creation of non-incremental backups if no parent is found). -#incremental yes - -# Specify after what time (in full hours after midnight) backups/ -# snapshots are considered as a daily backup/snapshot -#preserve_hour_of_day 0 - -# Specify on which day of week weekly/monthly backups are to be -# preserved. -#preserve_day_of_week sunday - -# Preserve all snapshots for a minimum period of time. -#snapshot_preserve_min 1d - -# Retention policy for the source snapshots. -#snapshot_preserve h d w m y - -# Preserve all backup targets for a minimum period of time. -#target_preserve_min no - -# Retention policy for backup targets: -#target_preserve h d w m y - -# Retention policy for archives ("btrbk archive" command): -#archive_preserve_min no -#archive_preserve h d w m y - -# Specify SSH private key for "ssh://" volumes / targets: -#ssh_identity /etc/btrbk/ssh/id_ed25519 -ssh_identity /root/.ssh/id_ed25519 -ssh_user root -ssh_compression no -#ssh_cipher_spec default - -compat_remote busybox -send_protocol 2 - -# Enable compression for remote btrfs send/receive operations: -stream_compress no -#stream_compress_level default -#stream_compress_threads default - -# Enable lock file support: Ensures that only one instance of btrbk -# can be run at a time. -lockfile /var/lock/btrbk.lock - -# Don't wait for transaction commit on deletion. Set this to "after" -# or "each" to make sure the deletion of subvolumes is committed to -# disk when btrbk terminates. -#btrfs_commit_delete no -# -# Volume section: "volume " -# -# Directory of a btrfs volume (or subvolume) -# containing the subvolume to be backuped -# (usually the mount-point of a btrfs filesystem -# mounted with subvolid=5 option) -# -# Subvolume section: "subvolume " -# -# Subvolume to be backuped, relative to -# in volume section. -# -# Target section: "target " -# -# (optional) type, defaults to "send-receive". -# Directory of a btrfs volume (or subvolume) -# receiving the backups. -# -# NOTE: The parser does not care about indentation, this is only for -# human readability. The options always apply to the last section -# encountered, overriding the corresponding option of the upper -# section. This means that the global options must be set before any -# "volume" section. -# -# -# Example configuration: -# -# Backup to external disk mounted on /mnt/btr_backup -#volume /mnt/btr_pool - # no action if external disk is not attached -# snapshot_create ondemand - - # propagates to all subvolume sections: -# target /mnt/btr_backup/_btrbk - -# subvolume root_gentoo -# subvolume kvm - # use different retention policy for kvm backups -# target_preserve 7d 4w - - -# Backup to external disk as well as some remote host -#volume /mnt/btr_data -# subvolume home - # always create snapshot, even if targets are unreachable -# snapshot_create always -# target /mnt/btr_backup/_btrbk -# target ssh://backup.my-remote-host.com/mnt/btr_backup - - -# Backup from remote host, with different naming -#volume ssh://my-remote-host.com/mnt/btr_pool -# subvolume data_0 -# snapshot_dir snapshots/btrbk -# snapshot_name data_main -# target /mnt/btr_backup/_btrbk/my-remote-host.com - - -# Resume backups from remote host which runs its own btrbk instance -# creating snapshots for "home" in "/mnt/btr_pool/btrbk_snapshots". -#volume ssh://my-remote-host.com/mnt/btr_pool -# snapshot_dir btrbk_snapshots -# snapshot_create no -# snapshot_preserve_min all -# subvolume home -# target /mnt/btr_backup/_btrbk/my-remote-host.com - -snapshot_preserve_min 2d -snapshot_preserve 14d - -target_preserve_min no -target_preserve 14d 10w *m - -archive_preserve_min latest -archive_preserve 12m 10y - -subvolume / - target_preserve 14d 10w 6m - snapshot_dir /.snapshots - target ssh://workstation/mnt/backup/laptop/root - # target ssh://router.lan/mnt/backup/laptop/root - -volume /home - subvolume bryan - # target /mnt/backup/laptop/home - target ssh://workstation/mnt/backup/laptop/home - # target ssh://router.lan/mnt/backup/laptop/home - diff --git a/roles/dotfiles/home/nautilus/.local/share/nautilus/scripts/share-link b/roles/dotfiles/nautilus/.local/share/nautilus/scripts/share-link similarity index 100% rename from roles/dotfiles/home/nautilus/.local/share/nautilus/scripts/share-link rename to roles/dotfiles/nautilus/.local/share/nautilus/scripts/share-link diff --git a/roles/dotfiles/root/dnf/etc/dnf/dnf.conf b/roles/dotfiles/root/dnf/etc/dnf/dnf.conf deleted file mode 100644 index 63f8982..0000000 --- a/roles/dotfiles/root/dnf/etc/dnf/dnf.conf +++ /dev/null @@ -1,8 +0,0 @@ -# see `man dnf.conf` for defaults and possible options - -[main] -# installonly_limit=3 -# best=False -skip_if_unavailable=True -deltarpm=True -fastestmirror=True diff --git a/roles/dotfiles/root/keyd/etc/keyd/default.conf b/roles/dotfiles/root/keyd/etc/keyd/default.conf deleted file mode 100644 index 1c61ce6..0000000 --- a/roles/dotfiles/root/keyd/etc/keyd/default.conf +++ /dev/null @@ -1,5 +0,0 @@ -[ids] -0001:0001:09b4e68d - -[main] -leftmeta+leftshift+f23 = rightcontrol \ No newline at end of file diff --git a/roles/dotfiles/root/pwrstatd/etc/pwrstatd.conf b/roles/dotfiles/root/pwrstatd/etc/pwrstatd.conf deleted file mode 100644 index 9c87bd8..0000000 --- a/roles/dotfiles/root/pwrstatd/etc/pwrstatd.conf +++ /dev/null @@ -1,131 +0,0 @@ -# -# pwrstatd configuration file -# - -# You must restart pwrstatd after changing this file in order for changes to take effect. -# Ex:/etc/init.d/pwrstatd restart - -# -# Action setting for event of Power Failure -# - -# A delay time in seconds since event of Power Failure occur then to run shell -# script and shutdown system. Allowed range is 0 ~ 3600. Default is 60 sec. -powerfail-delay = 60 - -# Enable to run shell script when the event of Power Failure occur. -# The allowed options are yes and no. Default is yes. -powerfail-active = no - -# Assign a path of script file for event of Power Failure. -# The default is /etc/pwrstatd-powerfail.sh -powerfail-cmd-path = /etc/pwrstatd-powerfail.sh - -# How much time in seconds to take script running for event of Power Failure. -# The allowed range is 0 ~ 3600. Default is 0 sec. -powerfail-duration = 0 - -# Allow Daemon to shutdown system for event of Power Failure. -# The allowed options are yes and no. Default is yes. -powerfail-shutdown = no - -# -# Action setting for event of Battery Low -# - -# A threshold of Battery Capacity, If the battery capacity is lower than this -# value and a event of Battery Low will be identified. The unit is percentage. -# The allowed range is 0 ~ 90. Default is 35 %. -lowbatt-threshold = 10 - -# A threshold of Remaining Runtime, If the Remaining Runtime is lower than this -# value and a event of Battery Low will be identified. The unit is second. -# The allowed range is 0 ~ 3600. Default is 300 sec. -# Note: When meet this condition the below 'shutdown-sustain' property -# will be ignored. -runtime-threshold = 180 - -# Enable to run shell script when the event of Battery Low occur. -# The allowed options are yes and no. Default is yes. -lowbatt-active = no - -# Assign a path of script file for event of Battery Low. -# The default is /etc/pwrstatd-lowbatt.sh -lowbatt-cmd-path = /etc/pwrstatd-lowbatt.sh - -# How much time in seconds to take script running for event of Battery Low. -# The allowed range is 0 ~ 60. Default is 0 sec. -lowbatt-duration = 0 - -# Allow Daemon to shutdown system for event of Battery Low. -# The allowed options are yes and no. Default is yes. -lowbatt-shutdown = yes - -# Turn UPS alarm on or off. -# The allowed options are yes and no. Default is yes. -enable-alarm = yes - -# The necessary time in seconds for system shutdown. -# The UPS will turn power off when this time is expired. -# The allowed range is 0 ~ 3600. Default is 600 sec.(10 min.) -# If the computer shutdown is cause by low runtime condition, the UPS will -# turn power off when the time is expired that time is assigned on -# 'runtime-threshold' property and it is no longer to refer the -# 'shutdown-sustain' property. -shutdown-sustain = 0 - -# Daemon will turn UPS power off once it ask system shutdown cause by a power -# event. Allowed options are yes and no. Default is yes. -turn-ups-off = no - -# The period of polling UPS in seconds. -# The allowed range is 1 ~ 60. Default is 3 sec. -ups-polling-rate = 5 - -# the period of re-try to find available UPS in seconds since find nothing at -# last time. The allowed range is 1 ~ 300. Default is 10 sec. -ups-retry-rate = 10 - -# Prohibiting daemon to provide communication mechanism for client, such as -# pwrstat command. normally, it should be 'no'. It can be 'yes' if any security -# consideration. Allowed options are yes and no. Default is no. -prohibit-client-access = no - -# The pwrstatd accepts four types of device node which includes the 'ttyS', -# 'ttyUSB', 'hiddev', and 'libusb' for communication with UPS. The pwrstatd -# defaults to enumerate all acceptable device nodes and pick up to use an -# available device node automatically. But this may cause a disturbance to the -# device node which is occupied by other software. Therefore, you can restrict -# this enumerate behave by using allowed-device-nodes option. You can assign -# the single device node path or multiple device node paths divided by a -# semicolon at this option. All groups of 'ttyS', 'ttyUSB', 'hiddev', or -# 'libusb' device node are enumerated without a suffix number assignment. -# Note, the 'libusb' does not support suffix number only. -# -# For example: restrict to use ttyS1, ttyS2 and hiddev1 device nodes at /dev -# path only. -# allowed-device-nodes = /dev/ttyS1;/dev/ttyS2;/dev/hiddev1 -# -# For example: restrict to use ttyS and ttyUSB two groups of device node at -# /dev,/dev/usb, and /dev/usb/hid paths(includes ttyS0 to ttySN and ttyUSB0 to -# ttyUSBN, N is number). -# allowed-device-nodes = ttyS;ttyUSB -# -# For example: restrict to use hiddev group of device node at /dev,/dev/usb, -# and /dev/usb/hid paths(includes hiddev0 to hiddevN, N is number). -# allowed-device-nodes = hiddev -# -# For example: restrict to use libusb device. -# allowed-device-nodes = libusb -allowed-device-nodes = - -# Daemon will hibernate system to instead of system shutdown when power -# event occur. Allowed options are yes and no. Default is no. -hibernate = no - -# Enable cloud solution. -# The allowed options are yes and no. Default is no. -cloud-active = no - -# Account for cloud server login. -cloud-account = \ No newline at end of file diff --git a/roles/dotfiles/root/sysconfig/etc/sysconfig/btrfsmaintenance b/roles/dotfiles/root/sysconfig/etc/sysconfig/btrfsmaintenance deleted file mode 100644 index cb5e13b..0000000 --- a/roles/dotfiles/root/sysconfig/etc/sysconfig/btrfsmaintenance +++ /dev/null @@ -1,154 +0,0 @@ -## Path: System/File systems/btrfs -## Type: string(none,stdout,journal,syslog) -## Default: "stdout" -# -# Output target for messages. Journal and syslog messages are tagged by the task name like -# 'btrfs-scrub' etc. -BTRFS_LOG_OUTPUT="journal" - -## Path: System/File systems/btrfs -## Type: string -## Default: "" -# -# Run periodic defrag on selected paths. The files from a given path do not -# cross mount points or other subvolumes/snapshots. If you want to defragment -# nested subvolumes, all have to be listed in this variable. -# (Colon separated paths) -BTRFS_DEFRAG_PATHS="" - -## Path: System/File systems/btrfs -## Type: string(none,daily,weekly,monthly) -## Default: "none" -## ServiceRestart: btrfsmaintenance-refresh -# -# Frequency of defrag. -BTRFS_DEFRAG_PERIOD="none" - -## Path: System/File systems/btrfs -## Type: string -## Default: "+1M" -# -# Minimal file size to consider for defragmentation -BTRFS_DEFRAG_MIN_SIZE="+1M" - -## Path: System/File systems/btrfs -## Type: string -## Default: "/" -# -# Which mountpoints/filesystems to balance periodically. This may reclaim unused -# portions of the filesystem and make the rest more compact. -# (Colon separated paths) -# The special word/mountpoint "auto" will evaluate all mounted btrfs -# filesystems -BTRFS_BALANCE_MOUNTPOINTS="auto" - -## Path: System/File systems/btrfs -## Type: string(none,daily,weekly,monthly) -## Default: "weekly" -## ServiceRestart: btrfsmaintenance-refresh -# -# Frequency of periodic balance. -# -# The frequency may be specified using one of the listed values or -# in the format documented in the "Calendar Events" section of systemd.time(7), -# if available. -BTRFS_BALANCE_PERIOD="weekly" - -## Path: System/File systems/btrfs -## Type: string -## Default: "5 10" -# -# The usage percent for balancing data block groups. -# -# Note: default values should not disturb normal work but may not reclaim -# enough block groups. If you observe that, add higher values but beware that -# this will increase IO load on the system. -BTRFS_BALANCE_DUSAGE="0 20 50 80" - -## Path: System/File systems/btrfs -## Type: string -## Default: "5" -# -# The usage percent for balancing metadata block groups. The values are also -# used in case the filesystem has mixed blockgroups. -# -# Note: default values should not disturb normal work but may not reclaim -# enough block groups. If you observe that, add higher values but beware that -# this will increase IO load on the system. -BTRFS_BALANCE_MUSAGE="80" - -## Path: System/File systems/btrfs -## Type: string -## Default: "/" -# -# Which mountpoints/filesystems to scrub periodically. -# (Colon separated paths) -# The special word/mountpoint "auto" will evaluate all mounted btrfs -# filesystems -BTRFS_SCRUB_MOUNTPOINTS="auto" - -## Path: System/File systems/btrfs -## Type: string(none,weekly,monthly) -## Default: "monthly" -## ServiceRestart: btrfsmaintenance-refresh -# -# Frequency of periodic scrub. -# -# The frequency may be specified using one of the listed values or -# in the format documented in the "Calendar Events" section of systemd.time(7), -# if available. -BTRFS_SCRUB_PERIOD="quarterly" - -## Path: System/File systems/btrfs -## Type: string(idle,normal) -## Default: "idle" -# -# Priority of IO at which the scrub process will run. Idle should not degrade -# performance but may take longer to finish. -BTRFS_SCRUB_PRIORITY="idle" - -## Path: System/File systems/btrfs -## Type: boolean -## Default: "false" -# -# Do read-only scrub and don't try to repair anything. -BTRFS_SCRUB_READ_ONLY="false" - -## Path: System/File systems/btrfs -## Description: Configuration for periodic fstrim -## Type: string(none,daily,weekly,monthly) -## Default: "none" -## ServiceRestart: btrfsmaintenance-refresh -# -# Frequency of periodic trim. Off by default so it does not collide with -# fstrim.timer . If you do not use the timer, turn it on here. The recommended -# period is 'weekly'. -# -# The frequency may be specified using one of the listed values or -# in the format documented in the "Calendar Events" section of systemd.time(7), -# if available. -BTRFS_TRIM_PERIOD="weekly" - -## Path: System/File systems/btrfs -## Description: Configuration for periodic fstrim - mountpoints -## Type: string -## Default: "/" -# -# Which mountpoints/filesystems to trim periodically. -# (Colon separated paths) -# The special word/mountpoint "auto" will evaluate all mounted btrfs -# filesystems -BTRFS_TRIM_MOUNTPOINTS="auto" - -## Path: System/File systems/btrfs -## Description: Configuration to allow concurrent jobs -## Type: boolean -## Default: "false" -# -# These maintenance tasks may compete for resources with each other, blocking -# out other tasks from using the file systems. This option will force -# these jobs to run in FIFO order when scheduled at overlapping times. This -# may include tasks scheduled to run when a system resumes or boots when -# the timer for these tasks(s) elapsed while the system was suspended -# or powered off. -BTRFS_ALLOW_CONCURRENCY="false" diff --git a/roles/dotfiles/home/ssh/.ssh/authorized_keys.j2 b/roles/dotfiles/ssh/.ssh/authorized_keys.j2 similarity index 100% rename from roles/dotfiles/home/ssh/.ssh/authorized_keys.j2 rename to roles/dotfiles/ssh/.ssh/authorized_keys.j2 diff --git a/roles/dotfiles/home/ssh/.ssh/config b/roles/dotfiles/ssh/.ssh/config similarity index 100% rename from roles/dotfiles/home/ssh/.ssh/config rename to roles/dotfiles/ssh/.ssh/config diff --git a/roles/dotfiles/tasks/main.yml b/roles/dotfiles/tasks/main.yml index 34dc6c7..435236f 100644 --- a/roles/dotfiles/tasks/main.yml +++ b/roles/dotfiles/tasks/main.yml @@ -1,20 +1,45 @@ --- -- name: Deploy selected home dotfile packages - ansible.builtin.include_tasks: ../../deploy_files.yml - vars: - var_prefix: dotfiles_home - subdir: "home/{{ item }}" - target_root: "{{ ansible_facts.env.HOME }}" - use_symlinks: true - become_root: false - loop: "{{ dotfiles_home_packages | default([]) }}" +- name: Discover dotfile packages + ansible.builtin.find: + paths: "{{ role_path }}" + file_type: directory + depth: 1 + excludes: ['tasks', 'templates', 'files', 'vars', 'defaults', 'meta', 'handlers'] + register: dotfiles_packages -- name: Deploy selected root dotfile packages - ansible.builtin.include_tasks: ../../deploy_files.yml - vars: - var_prefix: dotfiles_root - subdir: "root/{{ item }}" - target_root: "/" - use_symlinks: true - become_root: true - loop: "{{ dotfiles_root_packages | default([]) }}" +- name: Build complete file list + ansible.builtin.set_fact: + dotfiles_files: "{{ dotfiles_files | default([]) + lookup('community.general.filetree', item.path, wantlist=True) | selectattr('state', 'equalto', 'file') | list }}" + loop: "{{ dotfiles_packages.files }}" + +- name: Ensure dotfile directories exist + ansible.builtin.file: + path: "{{ ansible_facts.env.HOME }}/{{ item.path | dirname }}" + state: directory + mode: "0755" + loop: "{{ dotfiles_files }}" + when: item.path | dirname != '' + +- name: Deploy dotfiles (local with symlinks) + ansible.builtin.file: + src: "{{ item.src }}" + dest: "{{ ansible_facts.env.HOME }}/{{ item.path }}" + state: link + force: true + loop: "{{ dotfiles_files | rejectattr('path', 'match', '.*\\.j2$') | list }}" + when: ansible_connection in ['local', 'localhost'] + +- name: Deploy dotfiles (remote with copy) + ansible.builtin.copy: + src: "{{ item.src }}" + dest: "{{ ansible_facts.env.HOME }}/{{ item.path }}" + mode: preserve + loop: "{{ dotfiles_files | rejectattr('path', 'match', '.*\\.j2$') | list }}" + when: ansible_connection not in ['local', 'localhost'] + +- name: Render dotfile templates + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ ansible_facts.env.HOME }}/{{ item.path | replace('.j2', '') }}" + mode: preserve + loop: "{{ dotfiles_files | selectattr('path', 'match', '.*\\.j2$') | list }}" \ No newline at end of file diff --git a/roles/dotfiles/home/tmux/.tmux.conf b/roles/dotfiles/tmux/.tmux.conf similarity index 100% rename from roles/dotfiles/home/tmux/.tmux.conf rename to roles/dotfiles/tmux/.tmux.conf diff --git a/roles/dotfiles/home/vim/.vimrc b/roles/dotfiles/vim/.vimrc similarity index 100% rename from roles/dotfiles/home/vim/.vimrc rename to roles/dotfiles/vim/.vimrc diff --git a/roles/dotfiles/home/x2go/.x2goclient/sessions b/roles/dotfiles/x2go/.x2goclient/sessions similarity index 100% rename from roles/dotfiles/home/x2go/.x2goclient/sessions rename to roles/dotfiles/x2go/.x2goclient/sessions diff --git a/roles/dotfiles/home/zsh/.zshrc b/roles/dotfiles/zsh/.zshrc similarity index 100% rename from roles/dotfiles/home/zsh/.zshrc rename to roles/dotfiles/zsh/.zshrc diff --git a/roles/filesystems/tasks/main.yml b/roles/filesystems/tasks/main.yml index 05635fc..cb0a1f3 100644 --- a/roles/filesystems/tasks/main.yml +++ b/roles/filesystems/tasks/main.yml @@ -41,3 +41,11 @@ state: directory mode: "{{ item.mode | default('0755') }}" loop: "{{ directories | default([]) }}" + +- name: Deploy symlinks + ansible.builtin.file: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + state: link + force: true + loop: "{{ symlinks | default([]) }}" diff --git a/roles/quadlets/lazylibrarian.yml b/roles/quadlets/lazylibrarian.yml new file mode 100644 index 0000000..54af1db --- /dev/null +++ b/roles/quadlets/lazylibrarian.yml @@ -0,0 +1,145 @@ +quadlets: + - name: lazylibrarian + type: container + image: localhost/lazylibrarian:latest + volumes: + - "{{ config_root }}/lazylibrarian:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ media_root }}/ebooks:/ebooks:Z" + env: + TZ: "{{ tz }}" + command: ["/venv/bin/python", "/app/LazyLibrarian.py", "--nolaunch", "--port", "{{ lazylibrarian_port | default('5299') }}", "--datadir=/config"] + restart_policy: on-failure + +configs: + - path: "{{ config_root }}/lazylibrarian/lazylibrarian.cfg" + template: | + [GENERAL] + homepage = eBooks + auth_type = FORM + displaylength = -1 + series_tab = False + config_tab_num = 2 + toggles = False + launch_browser = False + imp_preflang = en, en-GB, en-US, eng, English, Unknown + date_lang = en_GB.UTF-8 + destination_copy = True + ebook_dir = {{ lazylibrarian_ebook_dir | default('/ebooks') }} + download_dir = {{ lazylibrarian_download_dir | default('/downloads/complete/lazylibrarian') }} + ebook_type = epub, mobi, pdf, azw3 + audiobook_type = mp3, m4b, opus, ogg + + [API] + api_enabled = True + api_key = {{ lazylibrarian_api_key }} + api_ro_key = {{ lazylibrarian_api_ro_key }} + book_api = GoodReads + ol_api = True + gb_api = {{ lazylibrarian_gb_api | default('') }} + gb_country = US + + [WEBSERVER] + http_user = {{ lazylibrarian_http_user | default('lazylibrarianuser') }} + http_pass = {{ lazylibrarian_http_pass }} + + [LOGGING] + logdir = {{ lazylibrarian_logdir | default('/config/Logs') }} + detaileduilog = True + + [IMPORTER] + multi_source = True + + [TELEMETRY] + server_id = {{ lazylibrarian_server_id | default('') }} + + [SABNZBD] + sab_host = {{ lazylibrarian_sab_host | default('localhost') }} + sab_port = {{ lazylibrarian_sab_port | default(8082) }} + sab_user = {{ sabnzbd_username | default('sabnzbduser') }} + sab_pass = {{ sabnzbd_password }} + sab_api = {{ sabnzbd_api_key }} + sab_cat = {{ lazylibrarian_sab_cat | default('lazylibrarian') }} + + [USENET] + nzb_downloader_sabnzbd = True + + [TORRENT] + tor_downloader_qbittorrent = True + seed_wait = False + + [QBITTORRENT] + qbittorrent_host = {{ lazylibrarian_qbit_host | default('localhost') }} + qbittorrent_port = {{ lazylibrarian_qbit_port | default(8082) }} + qbittorrent_user = {{ qbittorrent_username | default('qbittorrentuser') }} + qbittorrent_pass = {{ qbittorrent_password }} + qbittorrent_label = {{ lazylibrarian_qbit_label | default('lazylibrarian') }} + + [ANNA] + anna_key = {{ lazylibrarian_anna_key }} + anna = True + + [POSTPROCESS] + ebook_dest_folder = $Author/$Title $$ + audiobook_dest_folder = $Author/$Title + del_downloadfailed = True + + [MAGAZINES] + mag_tab = False + + [PROWL] + prowl_priority = -2 + + [PREPROCESS] + ebook_wanted_formats = azw3, mobi, epub + + {% for indexer in lazylibrarian_newznab_indexers | default([]) %} + [Newznab_{{ loop.index0 }}] + dispname = {{ indexer.name }} + enabled = {{ indexer.enabled | default(True) | string }} + host = {{ indexer.host }} + api = {{ indexer.api }} + generalsearch = search + bookcat = {{ indexer.bookcat | default('7020') }} + {% if indexer.magcat is defined %} + magcat = {{ indexer.magcat }} + {% endif %} + {% if indexer.comiccat is defined %} + comiccat = {{ indexer.comiccat }} + {% endif %} + updated = {{ indexer.updated | default('2026-01-27') }} + dlpriority = {{ indexer.dlpriority | default(26) }} + + {% endfor %} + {% for indexer in lazylibrarian_torznab_indexers | default([]) %} + [Torznab_{{ loop.index0 }}] + dispname = {{ indexer.name }} + enabled = {{ indexer.enabled | default(True) | string }} + host = {{ indexer.host }} + api = {{ indexer.api }} + generalsearch = search + {% if indexer.bookcat is defined %} + bookcat = {{ indexer.bookcat }} + {% endif %} + {% if indexer.magcat is defined %} + magcat = {{ indexer.magcat }} + {% endif %} + {% if indexer.comiccat is defined %} + comiccat = {{ indexer.comiccat }} + {% endif %} + updated = {{ indexer.updated | default('2026-01-27') }} + dlpriority = {{ indexer.dlpriority | default(26) }} + seeders = {{ indexer.seeders | default(1) }} + {% if indexer.seed_ratio is defined %} + seed_ratio = {{ indexer.seed_ratio }} + {% endif %} + + {% endfor %} + {% for indexer in lazylibrarian_generic_indexers | default([]) %} + [GEN_{{ loop.index0 }}] + dispname = {{ indexer.name }} + enabled = {{ indexer.enabled | default(True) | string }} + host = {{ indexer.host }} + search = {{ indexer.search }} + + {% endfor %} \ No newline at end of file diff --git a/roles/quadlets/lazylibrarian/config.ini.j2 b/roles/quadlets/lazylibrarian/config.ini.j2 deleted file mode 100644 index 7b47715..0000000 --- a/roles/quadlets/lazylibrarian/config.ini.j2 +++ /dev/null @@ -1,129 +0,0 @@ -[GENERAL] -homepage = eBooks -auth_type = FORM -displaylength = -1 -series_tab = False -config_tab_num = 2 -toggles = False -launch_browser = False -imp_preflang = en, en-GB, en-US, eng, English, Unknown -date_lang = en_GB.UTF-8 -destination_copy = True -ebook_dir = {{ lazylibrarian_ebook_dir | default('/ebooks') }} -download_dir = {{ lazylibrarian_download_dir | default('/downloads/complete/lazylibrarian') }} -ebook_type = epub, mobi, pdf, azw3 -audiobook_type = mp3, m4b, opus, ogg - -[API] -api_enabled = True -api_key = {{ lazylibrarian_api_key }} -api_ro_key = {{ lazylibrarian_api_ro_key }} -book_api = GoodReads -ol_api = True -gb_api = {{ lazylibrarian_gb_api | default('') }} -gb_country = US - -[WEBSERVER] -http_user = {{ lazylibrarian_http_user | default('lazylibrarianuser') }} -http_pass = {{ lazylibrarian_http_pass }} - -[LOGGING] -logdir = {{ lazylibrarian_logdir | default('/config/Logs') }} -detaileduilog = True - -[IMPORTER] -multi_source = True - -[TELEMETRY] -server_id = {{ lazylibrarian_server_id | default('') }} - -[SABNZBD] -sab_host = {{ lazylibrarian_sab_host | default('localhost') }} -sab_port = {{ lazylibrarian_sab_port | default(8082) }} -sab_user = {{ sabnzbd_username | default('sabnzbduser') }} -sab_pass = {{ sabnzbd_password }} -sab_api = {{ sabnzbd_api_key }} -sab_cat = {{ lazylibrarian_sab_cat | default('lazylibrarian') }} - -[USENET] -nzb_downloader_sabnzbd = True - -[TORRENT] -tor_downloader_qbittorrent = True -seed_wait = False - -[QBITTORRENT] -qbittorrent_host = {{ lazylibrarian_qbit_host | default('localhost') }} -qbittorrent_port = {{ lazylibrarian_qbit_port | default(8082) }} -qbittorrent_user = {{ qbittorrent_username | default('qbittorrentuser') }} -qbittorrent_pass = {{ qbittorrent_password }} -qbittorrent_label = {{ lazylibrarian_qbit_label | default('lazylibrarian') }} - -[ANNA] -anna_key = {{ lazylibrarian_anna_key }} -anna = True - -[POSTPROCESS] -ebook_dest_folder = $Author/$Title $$ -audiobook_dest_folder = $Author/$Title -del_downloadfailed = True - -[MAGAZINES] -mag_tab = False - -[PROWL] -prowl_priority = -2 - -[PREPROCESS] -ebook_wanted_formats = azw3, mobi, epub - -{% for indexer in lazylibrarian_newznab_indexers | default([]) %} -[Newznab_{{ loop.index0 }}] -dispname = {{ indexer.name }} -enabled = {{ indexer.enabled | default(True) | string }} -host = {{ indexer.host }} -api = {{ indexer.api }} -generalsearch = search -bookcat = {{ indexer.bookcat | default('7020') }} -{% if indexer.magcat is defined %} -magcat = {{ indexer.magcat }} -{% endif %} -{% if indexer.comiccat is defined %} -comiccat = {{ indexer.comiccat }} -{% endif %} -updated = {{ indexer.updated | default('2026-01-27') }} -dlpriority = {{ indexer.dlpriority | default(26) }} - -{% endfor %} -{% for indexer in lazylibrarian_torznab_indexers | default([]) %} -[Torznab_{{ loop.index0 }}] -dispname = {{ indexer.name }} -enabled = {{ indexer.enabled | default(True) | string }} -host = {{ indexer.host }} -api = {{ indexer.api }} -generalsearch = search -{% if indexer.bookcat is defined %} -bookcat = {{ indexer.bookcat }} -{% endif %} -{% if indexer.magcat is defined %} -magcat = {{ indexer.magcat }} -{% endif %} -{% if indexer.comiccat is defined %} -comiccat = {{ indexer.comiccat }} -{% endif %} -updated = {{ indexer.updated | default('2026-01-27') }} -dlpriority = {{ indexer.dlpriority | default(26) }} -seeders = {{ indexer.seeders | default(1) }} -{% if indexer.seed_ratio is defined %} -seed_ratio = {{ indexer.seed_ratio }} -{% endif %} - -{% endfor %} -{% for indexer in lazylibrarian_generic_indexers | default([]) %} -[GEN_{{ loop.index0 }}] -dispname = {{ indexer.name }} -enabled = {{ indexer.enabled | default(True) | string }} -host = {{ indexer.host }} -search = {{ indexer.search }} - -{% endfor %} \ No newline at end of file diff --git a/roles/quadlets/lazylibrarian/quadlets.yml b/roles/quadlets/lazylibrarian/quadlets.yml deleted file mode 100644 index 0437c0e..0000000 --- a/roles/quadlets/lazylibrarian/quadlets.yml +++ /dev/null @@ -1,11 +0,0 @@ -- name: lazylibrarian - type: container - image: localhost/lazylibrarian:latest - volumes: - - "{{ config_root }}/lazylibrarian:/config:Z" - - "{{ download_root }}/htpc:/downloads:z" - - "{{ media_root }}/ebooks:/ebooks:Z" - env: - TZ: "{{ tz }}" - command: ["/venv/bin/python", "/app/LazyLibrarian.py", "--nolaunch", "--port", "{{ lazylibrarian_port | default('5299') }}", "--datadir=/config"] - restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/lidarr.yml b/roles/quadlets/lidarr.yml new file mode 100644 index 0000000..36da923 --- /dev/null +++ b/roles/quadlets/lidarr.yml @@ -0,0 +1,49 @@ +quadlets: + - name: lidarr + type: build + image: localhost/lidarr:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + icu-libs libintl sqlite-libs curl libmediainfo xmlstarlet jq \ + && url=$(curl -sL "https://api.github.com/repos/Lidarr/Lidarr/releases/latest" \ + | jq -r '.assets[] | select(.name | test("linux-musl-core-x64.tar.gz$")) | .browser_download_url') \ + && [ -n "$url" ] \ + && curl -L -o /tmp/Lidarr.tar.gz "$url" \ + && mkdir -p /app && tar -xzf /tmp/Lidarr.tar.gz --strip-components=1 -C /app \ + && chmod +x /app/Lidarr \ + && rm /tmp/Lidarr.tar.gz + WORKDIR /app + + - name: lidarr + type: container + image: localhost/lidarr:latest + volumes: + - "{{ config_root }}/lidarr:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ media_root }}/music:/music:Z" + env: + TZ: "{{ tz }}" + LIDARR__APP__LAUNCHBROWSER: false + LIDARR__APP__INSTANCENAME: "{{ LIDARR__APP__INSTANCENAME | default('Lidarr') }}" + LIDARR__AUTH__METHOD: "{{ LIDARR__AUTH__METHOD | default('Forms') }}" + LIDARR__AUTH__APIKEY: "{{ LIDARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" + LIDARR__AUTH__ENABLED: "{{ LIDARR__AUTH__ENABLED | default(true) }}" + LIDARR__AUTH__REQUIRED: "{{ LIDARR__AUTH__REQUIRED | default('DisabledForLocalAddresses') }}" + LIDARR__SERVER__ENABLESSL: "{{ LIDARR__SERVER__ENABLESSL | default(false) }}" + LIDARR__SERVER__PORT: "{{ LIDARR__SERVER__PORT | default('8686') }}" + LIDARR__SERVER__SSLPORT: "{{ LIDARR__SERVER__SSLPORT | default('6868') }}" + LIDARR__SERVER__BINDADDRESS: "{{ LIDARR__SERVER__BINDADDRESS | default('*') }}" + LIDARR__SERVER__SSLCERTPATH: "{{ LIDARR__SERVER__SSLCERTPATH | default('/config/ssl/server.crt') }}" + LIDARR__SERVER__SSLCERTPASSWORD: "{{ LIDARR__SERVER__SSLCERTPASSWORD | default('/config/ssl/server.key') }}" + LIDARR__LOG__ANALYTICSENABLED: "{{ LIDARR__LOG__ANALYTICSENABLED | default(false) }}" + LIDARR__LOG__LEVEL: "{{ LIDARR__LOG__LEVEL | default('info') }}" + LIDARR__UPDATE__AUTOMATICALLY: "{{ LIDARR__UPDATE__AUTOMATICALLY | default(false) }}" + command: ["/app/Lidarr", "-nobrowser", "--data=/config"] + restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/lidarr/quadlets.yml b/roles/quadlets/lidarr/quadlets.yml deleted file mode 100644 index 53f0c8d..0000000 --- a/roles/quadlets/lidarr/quadlets.yml +++ /dev/null @@ -1,48 +0,0 @@ -- name: lidarr - type: build - image: localhost/lidarr:latest - pull: missing - format: oci - force_rm: true - container_file: | - FROM {{ alpine_base_image }} - LABEL maintainer="{{ maintainer }}" - RUN apk add --no-cache \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ - icu-libs libintl sqlite-libs curl libmediainfo xmlstarlet jq \ - && url=$(curl -sL "https://api.github.com/repos/Lidarr/Lidarr/releases/latest" \ - | jq -r '.assets[] | select(.name | test("linux-musl-core-x64.tar.gz$")) | .browser_download_url') \ - && [ -n "$url" ] \ - && curl -L -o /tmp/Lidarr.tar.gz "$url" \ - && mkdir -p /app && tar -xzf /tmp/Lidarr.tar.gz --strip-components=1 -C /app \ - && chmod +x /app/Lidarr \ - && rm /tmp/Lidarr.tar.gz - WORKDIR /app - -- name: lidarr - type: container - image: localhost/lidarr:latest - volumes: - - "{{ config_root }}/lidarr:/config:Z" - - "{{ download_root }}/htpc:/downloads:z" - - "{{ media_root }}/music:/music:Z" - env: - TZ: "{{ tz }}" - LIDARR__APP__LAUNCHBROWSER: false - LIDARR__APP__INSTANCENAME: "{{ LIDARR__APP__INSTANCENAME | default('Lidarr') }}" - LIDARR__AUTH__METHOD: "{{ LIDARR__AUTH__METHOD | default('Forms') }}" - LIDARR__AUTH__APIKEY: "{{ LIDARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" - LIDARR__AUTH__ENABLED: "{{ LIDARR__AUTH__ENABLED | default(true) }}" - LIDARR__AUTH__REQUIRED: "{{ LIDARR__AUTH__REQUIRED | default('DisabledForLocalAddresses') }}" - LIDARR__SERVER__ENABLESSL: "{{ LIDARR__SERVER__ENABLESSL | default(false) }}" - LIDARR__SERVER__PORT: "{{ LIDARR__SERVER__PORT | default('8686') }}" - LIDARR__SERVER__SSLPORT: "{{ LIDARR__SERVER__SSLPORT | default('6868') }}" - LIDARR__SERVER__BINDADDRESS: "{{ LIDARR__SERVER__BINDADDRESS | default('*') }}" - LIDARR__SERVER__SSLCERTPATH: "{{ LIDARR__SERVER__SSLCERTPATH | default('/config/ssl/server.crt') }}" - LIDARR__SERVER__SSLCERTPASSWORD: "{{ LIDARR__SERVER__SSLCERTPASSWORD | default('/config/ssl/server.key') }}" - LIDARR__LOG__ANALYTICSENABLED: "{{ LIDARR__LOG__ANALYTICSENABLED | default(false) }}" - LIDARR__LOG__LEVEL: "{{ LIDARR__LOG__LEVEL | default('info') }}" - LIDARR__UPDATE__AUTOMATICALLY: "{{ LIDARR__UPDATE__AUTOMATICALLY | default(false) }}" - command: ["/app/Lidarr", "-nobrowser", "--data=/config"] - restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/prowlarr.yml b/roles/quadlets/prowlarr.yml new file mode 100644 index 0000000..9c0d6d2 --- /dev/null +++ b/roles/quadlets/prowlarr.yml @@ -0,0 +1,47 @@ +--- + +quadlets: + - name: prowlarr + type: build + image: localhost/prowlarr:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + libintl icu-libs sqlite-libs curl jq \ + && url=$(curl -sL "https://api.github.com/repos/Prowlarr/Prowlarr/releases/latest" \ + | jq -r '.assets[] | select(.name | test("linux-musl-core-x64.tar.gz$")) | .browser_download_url') \ + && [ -n "$url" ] \ + && curl -L -o /tmp/Prowlarr.tar.gz "$url" \ + && mkdir -p /app \ + && tar -xzf /tmp/Prowlarr.tar.gz -C /app --strip-components=1 \ + && rm /tmp/Prowlarr.tar.gz + WORKDIR /app + + - name: prowlarr + type: container + image: localhost/prowlarr:latest + volumes: + - "{{ config_root }}/prowlarr:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + env: + TZ: "{{ tz }}" + PROWLARR__APP__LAUNCHBROWSER: false + PROWLARR__APP__INSTANCENAME: "{{ PROWLARR__APP__INSTANCENAME | default('Prowlarr') }}" + PROWLARR__AUTH__METHOD: "{{ PROWLARR__AUTH__METHOD | default('Forms') }}" + PROWLARR__AUTH__REQUIRED: "{{ PROWLARR__AUTH__REQUIRED | default('DisabledForLocalAddresses') }}" + PROWLARR__AUTH__APIKEY: "{{ PROWLARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" + PROWLARR__SERVER__ENABLESSL: "{{ PROWLARR__SERVER__ENABLESSL | default(false) }}" + PROWLARR__SERVER__SSLPORT: "{{ PROWLARR__SERVER__PORT | default('6969') }}" + PROWLARR__SERVER__PORT: "{{ PROWLARR__SERVER__PORT | default('9696') }}" + PROWLARR__SERVER__BINDADDRESS: "{{ PROWLARR__SERVER__BINDADDRESS | default('*') }}" + PROWLARR__LOG__ANALYTICSENABLED: "{{ PROWLARR__LOG__ANALYTICSENABLED | default(false) }}" + PROWLARR__LOG__LEVEL: "{{ PROWLARR__LOG__LEVEL | default('info') }}" + PROWLARR__UPDATE__AUTOMATICALLY: "{{ PROWLARR__UPDATE__AUTOMATICALLY | default(false) }}" + command: ["/app/Prowlarr", "--nobrowser", "--data=/config"] + restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/prowlarr/quadlets.yml b/roles/quadlets/prowlarr/quadlets.yml deleted file mode 100644 index f5b3e57..0000000 --- a/roles/quadlets/prowlarr/quadlets.yml +++ /dev/null @@ -1,44 +0,0 @@ -- name: prowlarr - type: build - image: localhost/prowlarr:latest - pull: missing - format: oci - force_rm: true - container_file: | - FROM {{ alpine_base_image }} - LABEL maintainer="{{ maintainer }}" - RUN apk add --no-cache \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ - libintl icu-libs sqlite-libs curl jq \ - && url=$(curl -sL "https://api.github.com/repos/Prowlarr/Prowlarr/releases/latest" \ - | jq -r '.assets[] | select(.name | test("linux-musl-core-x64.tar.gz$")) | .browser_download_url') \ - && [ -n "$url" ] \ - && curl -L -o /tmp/Prowlarr.tar.gz "$url" \ - && mkdir -p /app \ - && tar -xzf /tmp/Prowlarr.tar.gz -C /app --strip-components=1 \ - && rm /tmp/Prowlarr.tar.gz - WORKDIR /app - -- name: prowlarr - type: container - image: localhost/prowlarr:latest - volumes: - - "{{ config_root }}/prowlarr:/config:Z" - - "{{ download_root }}/htpc:/downloads:z" - env: - TZ: "{{ tz }}" - PROWLARR__APP__LAUNCHBROWSER: false - PROWLARR__APP__INSTANCENAME: "{{ PROWLARR__APP__INSTANCENAME | default('Prowlarr') }}" - PROWLARR__AUTH__METHOD: "{{ PROWLARR__AUTH__METHOD | default('Forms') }}" - PROWLARR__AUTH__REQUIRED: "{{ PROWLARR__AUTH__REQUIRED | default('DisabledForLocalAddresses') }}" - PROWLARR__AUTH__APIKEY: "{{ PROWLARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" - PROWLARR__SERVER__ENABLESSL: "{{ PROWLARR__SERVER__ENABLESSL | default(false) }}" - PROWLARR__SERVER__SSLPORT: "{{ PROWLARR__SERVER__PORT | default('6969') }}" - PROWLARR__SERVER__PORT: "{{ PROWLARR__SERVER__PORT | default('9696') }}" - PROWLARR__SERVER__BINDADDRESS: "{{ PROWLARR__SERVER__BINDADDRESS | default('*') }}" - PROWLARR__LOG__ANALYTICSENABLED: "{{ PROWLARR__LOG__ANALYTICSENABLED | default(false) }}" - PROWLARR__LOG__LEVEL: "{{ PROWLARR__LOG__LEVEL | default('info') }}" - PROWLARR__UPDATE__AUTOMATICALLY: "{{ PROWLARR__UPDATE__AUTOMATICALLY | default(false) }}" - command: ["/app/Prowlarr", "--nobrowser", "--data=/config"] - restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/qbittorrent.yml b/roles/quadlets/qbittorrent.yml new file mode 100644 index 0000000..83455ac --- /dev/null +++ b/roles/quadlets/qbittorrent.yml @@ -0,0 +1,162 @@ +quadlets: + - name: qbittorrent + type: build + image: localhost/qbittorrent:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + qbittorrent-nox \ + && mkdir -p /app \ + && ln -s /usr/bin/qbittorrent-nox /app/qbittorrent-nox + WORKDIR /app + + - name: qbittorrent + type: container + image: localhost/qbittorrent:latest + volumes: + - "{{ config_root }}/qbittorrent:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ monitor_root }}/torrents:/torrents:Z" + env: + TZ: "{{ tz }}" + command: + - "qbittorrent-nox" + - "--profile=/config" + restart_policy: on-failure + +configs: + - path: "{{ config_root }}/qbittorrent/config/qBittorrent.conf" + template: | + [Application] + FileLogger\Age=1 + FileLogger\AgeType=1 + FileLogger\Backup=true + FileLogger\DeleteOld=true + FileLogger\Enabled=false + FileLogger\MaxSizeBytes=66560 + FileLogger\Path=/config/qBittorrent/data/logs + MemoryWorkingSetLimit=2048 + + [AutoRun] + OnTorrentAdded\Enabled=false + OnTorrentAdded\Program= + enabled=false + program= + + [BitTorrent] + MergeTrackersEnabled={{ qbittorrent_merge_trackers | default(false) | lower }} + Session\AddExtensionToIncompleteFiles=true + Session\AddTorrentStopped=false + Session\AddTrackersEnabled={{ qbittorrent_add_trackers | default(false) | lower }} + Session\AdditionalTrackers={{ qbittorrent_additional_trackers | default('') }} + Session\AlternativeGlobalDLSpeedLimit={{ qbittorrent_alt_dl_limit | default(0) }} + Session\AlternativeGlobalUPSpeedLimit={{ qbittorrent_alt_up_limit | default(0) }} + Session\AnonymousModeEnabled={{ qbittorrent_anonymous_mode | default(true) | lower }} + Session\DefaultSavePath={{ qbittorrent_complete_dir | default('/downloads/complete') }} + Session\DisableAutoTMMByDefault=false + Session\DisableAutoTMMTriggers\CategorySavePathChanged=false + Session\DisableAutoTMMTriggers\DefaultSavePathChanged=false + Session\ExcludedFileNames= + Session\GlobalDLSpeedLimit={{ qbittorrent_dl_limit | default(0) }} + Session\GlobalMaxRatio={{ qbittorrent_max_ratio | default(1) }} + Session\GlobalMaxSeedingMinutes={{ qbittorrent_max_seed_minutes | default(0) }} + Session\GlobalUPSpeedLimit={{ qbittorrent_ul_limit | default(300) }} + Session\IgnoreLimitsOnLAN=true + Session\IgnoreSlowTorrentsForQueueing=true + Session\MaxActiveDownloads={{ qbittorrent_max_active_downloads | default(0) }} + Session\MaxActiveTorrents={{ qbittorrent_max_active_torrents | default(0) }} + Session\Port={{ qbittorrent_session_port | default(48442) }} + Session\QueueingSystemEnabled={{ qbittorrent_queueing_enabled | default(false) | lower }} + Session\SSL\Port={{ qbittorrent_ssl_port | default('11192') }} + Session\ShareLimitAction={{ qbittorrent_share_limit_action | default('Stop') }} + Session\TempPath={{ qbittorrent_temp_dir | default('/downloads/incomplete/qbittorrent') }} + Session\TempPathEnabled=true + Session\UseAlternativeGlobalSpeedLimit=true + + [Core] + AutoDeleteAddedTorrentFile=IfAdded + + [LegalNotice] + Accepted=true + + [Meta] + MigrationVersion=8 + + [Network] + Cookies=@Invalid() + Proxy\HostnameLookupEnabled=false + Proxy\Profiles\BitTorrent=true + Proxy\Profiles\Misc=true + Proxy\Profiles\RSS=true + + [Preferences] + Advanced\AnonymousMode={{ qbittorrent_anonymous_mode | default(true) | lower }} + Advanced\RecheckOnCompletion={{ qbittorrent_recheck_on_completion | default(false) | lower }} + Advanced\trackerPort={{ qbittorrent_tracker_port | default(9000) }} + Advanced\trackerPortForwarding=false + Bittorrent\MaxRatio={{ qbittorrent_max_ratio | default(1) }} + Connection\GlobalDLLimitAlt={{ qbittorrent_global_dl_limit_alt | default(0) }} + Connection\GlobalUPLimitAlt={{ qbittorrent_global_up_limit_alt | default(0) }} + Connection\PortRangeMin={{ qbittorrent_port_range_min | default(48442) }} + Connection\ResolvePeerCountries=true + Downloads\SavePath={{ qbittorrent_complete_dir | default('/downloads/complete') }} + Downloads\ScanDirsLastPath={{ qbittorrent_scan_dir | default('/torrents') }} + Downloads\ScanDirsV2=@Variant(\0\0\0\x1c\0\0\0\0) + Downloads\TempPath={{ qbittorrent_temp_dir | default('/downloads/incomplete/qbittorrent') }} + Downloads\TempPathEnabled=true + Downloads\UseIncompleteExtension=true + DynDNS\DomainName=changeme.dyndns.org + DynDNS\Enabled=false + DynDNS\Password= + DynDNS\Service=DynDNS + DynDNS\Username= + General\Locale={{ qbittorrent_locale | default('en') }} + MailNotification\email= + MailNotification\enabled=false + MailNotification\password= + MailNotification\req_auth=true + MailNotification\req_ssl=false + MailNotification\sender=qBittorrent_notification@example.com + MailNotification\smtp_server=smtp.changeme.com + MailNotification\username= + Queueing\IgnoreSlowTorrents=true + Queueing\MaxActiveDownloads={{ qbittorrent_max_active_downloads | default(20) }} + Queueing\MaxActiveTorrents={{ qbittorrent_max_active_torrents | default(20) }} + Queueing\QueueingEnabled=true + WebUI\Address={{ qbittorrent_host | default('') }} + WebUI\AlternativeUIEnabled=false + WebUI\AuthSubnetWhitelist={{ qbittorrent_subnet_whitelist | default('') }} + WebUI\AuthSubnetWhitelistEnabled=true + WebUI\BanDuration=3600 + WebUI\CSRFProtection=true + WebUI\ClickjackingProtection=true + WebUI\CustomHTTPHeaders= + WebUI\CustomHTTPHeadersEnabled=false + WebUI\Enabled=true + WebUI\HTTPS\CertificatePath={{ qbittorrent_https_cert | default('/config/qBittorrent/config/ssl/server.crt') }} + WebUI\HTTPS\Enabled={{ qbittorrent_enable_https | default(false) | lower }} + WebUI\HTTPS\KeyPath={{ qbittorrent_https_key | default('/config/qBittorrent/config/ssl/server.key') }} + WebUI\HostHeaderValidation=false + WebUI\LocalHostAuth=false + WebUI\MaxAuthenticationFailCount=5 + WebUI\Password_PBKDF2="{{ qbittorrent_password_pbkdf2 | default('') }}" + WebUI\Password_ha1={{ qbittorrent_password_ha1 | default('') }} + WebUI\Port={{ qbittorrent_ui_port | default(8082) }} + WebUI\ReverseProxySupportEnabled=false + WebUI\RootFolder= + WebUI\SecureCookie=true + WebUI\ServerDomains={{ qbittorrent_server_domains | default('*') }} + WebUI\SessionTimeout=3600 + WebUI\TrustedReverseProxiesList= + WebUI\UseUPnP=true + WebUI\Username={{ qbittorrent_username | default('qbittorrentuser') }} + + [RSS] + AutoDownloader\DownloadRepacks={{ qbittorrent_download_repacks | default(true) | lower }} + AutoDownloader\SmartEpisodeFilter=s(\\d+)e(\\d+), (\\d+)x(\\d+), "(\\d{4}[.\\-]\\d{1,2}[.\\-]\\d{1,2})", "(\\d{1,2}[.\\-]\\d{1,2}[.\\-]\\d{4})" diff --git a/roles/quadlets/qbittorrent/qBittorrent/config/qBittorrent.conf.j2 b/roles/quadlets/qbittorrent/qBittorrent/config/qBittorrent.conf.j2 deleted file mode 100644 index 5d1c598..0000000 --- a/roles/quadlets/qbittorrent/qBittorrent/config/qBittorrent.conf.j2 +++ /dev/null @@ -1,127 +0,0 @@ -[Application] -FileLogger\Age=1 -FileLogger\AgeType=1 -FileLogger\Backup=true -FileLogger\DeleteOld=true -FileLogger\Enabled=false -FileLogger\MaxSizeBytes=66560 -FileLogger\Path=/config/qBittorrent/data/logs -MemoryWorkingSetLimit=2048 - -[AutoRun] -OnTorrentAdded\Enabled=false -OnTorrentAdded\Program= -enabled=false -program= - -[BitTorrent] -MergeTrackersEnabled={{ qbittorrent_merge_trackers | default(false) | lower }} -Session\AddExtensionToIncompleteFiles=true -Session\AddTorrentStopped=false -Session\AddTrackersEnabled={{ qbittorrent_add_trackers | default(false) | lower }} -Session\AdditionalTrackers={{ qbittorrent_additional_trackers | default('') }} -Session\AlternativeGlobalDLSpeedLimit={{ qbittorrent_alt_dl_limit | default(0) }} -Session\AlternativeGlobalUPSpeedLimit={{ qbittorrent_alt_up_limit | default(0) }} -Session\AnonymousModeEnabled={{ qbittorrent_anonymous_mode | default(true) | lower }} -Session\DefaultSavePath={{ qbittorrent_complete_dir | default('/downloads/complete') }} -Session\DisableAutoTMMByDefault=false -Session\DisableAutoTMMTriggers\CategorySavePathChanged=false -Session\DisableAutoTMMTriggers\DefaultSavePathChanged=false -Session\ExcludedFileNames= -Session\GlobalDLSpeedLimit={{ qbittorrent_dl_limit | default(0) }} -Session\GlobalMaxRatio={{ qbittorrent_max_ratio | default(1) }} -Session\GlobalMaxSeedingMinutes={{ qbittorrent_max_seed_minutes | default(0) }} -Session\GlobalUPSpeedLimit={{ qbittorrent_ul_limit | default(300) }} -Session\IgnoreLimitsOnLAN=true -Session\IgnoreSlowTorrentsForQueueing=true -Session\MaxActiveDownloads={{ qbittorrent_max_active_downloads | default(0) }} -Session\MaxActiveTorrents={{ qbittorrent_max_active_torrents | default(0) }} -Session\Port={{ qbittorrent_session_port | default(48442) }} -Session\QueueingSystemEnabled={{ qbittorrent_queueing_enabled | default(false) | lower }} -Session\SSL\Port={{ qbittorrent_ssl_port | default('11192') }} -Session\ShareLimitAction={{ qbittorrent_share_limit_action | default('Stop') }} -Session\TempPath={{ qbittorrent_temp_dir | default('/downloads/incomplete/qbittorrent') }} -Session\TempPathEnabled=true -Session\UseAlternativeGlobalSpeedLimit=true - -[Core] -AutoDeleteAddedTorrentFile=IfAdded - -[LegalNotice] -Accepted=true - -[Meta] -MigrationVersion=8 - -[Network] -Cookies=@Invalid() -Proxy\HostnameLookupEnabled=false -Proxy\Profiles\BitTorrent=true -Proxy\Profiles\Misc=true -Proxy\Profiles\RSS=true - -[Preferences] -Advanced\AnonymousMode={{ qbittorrent_anonymous_mode | default(true) | lower }} -Advanced\RecheckOnCompletion={{ qbittorrent_recheck_on_completion | default(false) | lower }} -Advanced\trackerPort={{ qbittorrent_tracker_port | default(9000) }} -Advanced\trackerPortForwarding=false -Bittorrent\MaxRatio={{ qbittorrent_max_ratio | default(1) }} -Connection\GlobalDLLimitAlt={{ qbittorrent_global_dl_limit_alt | default(0) }} -Connection\GlobalUPLimitAlt={{ qbittorrent_global_up_limit_alt | default(0) }} -Connection\PortRangeMin={{ qbittorrent_port_range_min | default(48442) }} -Connection\ResolvePeerCountries=true -Downloads\SavePath={{ qbittorrent_complete_dir | default('/downloads/complete') }} -Downloads\ScanDirsLastPath={{ qbittorrent_scan_dir | default('/torrents') }} -Downloads\ScanDirsV2=@Variant(\0\0\0\x1c\0\0\0\0) -Downloads\TempPath={{ qbittorrent_temp_dir | default('/downloads/incomplete/qbittorrent') }} -Downloads\TempPathEnabled=true -Downloads\UseIncompleteExtension=true -DynDNS\DomainName=changeme.dyndns.org -DynDNS\Enabled=false -DynDNS\Password= -DynDNS\Service=DynDNS -DynDNS\Username= -General\Locale={{ qbittorrent_locale | default('en') }} -MailNotification\email= -MailNotification\enabled=false -MailNotification\password= -MailNotification\req_auth=true -MailNotification\req_ssl=false -MailNotification\sender=qBittorrent_notification@example.com -MailNotification\smtp_server=smtp.changeme.com -MailNotification\username= -Queueing\IgnoreSlowTorrents=true -Queueing\MaxActiveDownloads={{ qbittorrent_max_active_downloads | default(20) }} -Queueing\MaxActiveTorrents={{ qbittorrent_max_active_torrents | default(20) }} -Queueing\QueueingEnabled=true -WebUI\Address={{ qbittorrent_host | default('') }} -WebUI\AlternativeUIEnabled=false -WebUI\AuthSubnetWhitelist={{ qbittorrent_subnet_whitelist | default('') }} -WebUI\AuthSubnetWhitelistEnabled=true -WebUI\BanDuration=3600 -WebUI\CSRFProtection=true -WebUI\ClickjackingProtection=true -WebUI\CustomHTTPHeaders= -WebUI\CustomHTTPHeadersEnabled=false -WebUI\Enabled=true -WebUI\HTTPS\CertificatePath={{ qbittorrent_https_cert | default('/config/qBittorrent/config/ssl/server.crt') }} -WebUI\HTTPS\Enabled={{ qbittorrent_enable_https | default(false) | lower }} -WebUI\HTTPS\KeyPath={{ qbittorrent_https_key | default('/config/qBittorrent/config/ssl/server.key') }} -WebUI\HostHeaderValidation=false -WebUI\LocalHostAuth=false -WebUI\MaxAuthenticationFailCount=5 -WebUI\Password_PBKDF2="{{ qbittorrent_password_pbkdf2 | default('') }}" -WebUI\Password_ha1={{ qbittorrent_password_ha1 | default('') }} -WebUI\Port={{ qbittorrent_ui_port | default(8082) }} -WebUI\ReverseProxySupportEnabled=false -WebUI\RootFolder= -WebUI\SecureCookie=true -WebUI\ServerDomains={{ qbittorrent_server_domains | default('*') }} -WebUI\SessionTimeout=3600 -WebUI\TrustedReverseProxiesList= -WebUI\UseUPnP=true -WebUI\Username={{ qbittorrent_username | default('qbittorrentuser') }} - -[RSS] -AutoDownloader\DownloadRepacks={{ qbittorrent_download_repacks | default(true) | lower }} -AutoDownloader\SmartEpisodeFilter=s(\\d+)e(\\d+), (\\d+)x(\\d+), "(\\d{4}[.\\-]\\d{1,2}[.\\-]\\d{1,2})", "(\\d{1,2}[.\\-]\\d{1,2}[.\\-]\\d{4})" diff --git a/roles/quadlets/qbittorrent/quadlets.yml b/roles/quadlets/qbittorrent/quadlets.yml deleted file mode 100644 index a065fb0..0000000 --- a/roles/quadlets/qbittorrent/quadlets.yml +++ /dev/null @@ -1,30 +0,0 @@ -- name: qbittorrent - type: build - image: localhost/qbittorrent:latest - pull: missing - format: oci - force_rm: true - container_file: | - FROM {{ alpine_base_image }} - LABEL maintainer="{{ maintainer }}" - RUN apk add --no-cache \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ - qbittorrent-nox \ - && mkdir -p /app \ - && ln -s /usr/bin/qbittorrent-nox /app/qbittorrent-nox - WORKDIR /app - -- name: qbittorrent - type: container - image: localhost/qbittorrent:latest - volumes: - - "{{ config_root }}/qbittorrent:/config:Z" - - "{{ download_root }}/htpc:/downloads:z" - - "{{ monitor_root }}/torrents:/torrents:Z" - env: - TZ: "{{ tz }}" - command: - - "qbittorrent-nox" - - "--profile=/config" - restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/radarr.yml b/roles/quadlets/radarr.yml new file mode 100644 index 0000000..2f75c1d --- /dev/null +++ b/roles/quadlets/radarr.yml @@ -0,0 +1,46 @@ +quadlets: + - name: radarr + type: build + image: localhost/radarr:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + icu-libs libintl sqlite-libs curl libmediainfo xmlstarlet jq \ + && url=$(curl -sL "https://api.github.com/repos/Radarr/Radarr/releases/latest" \ + | jq -r '.assets[] | select(.name | test("linux-musl-core-x64.tar.gz$")) | .browser_download_url') \ + && curl -L -o /tmp/radarr.tar.gz "$url" \ + && mkdir -p /app \ + && tar -xzf /tmp/radarr.tar.gz --strip-components=1 -C /app \ + && chmod +x /app/Radarr \ + && rm -rf /app/Radarr.Update + WORKDIR /app + + - name: radarr + type: container + image: localhost/radarr:latest + volumes: + - "{{ config_root }}/radarr:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ media_root }}/movies:/movies:Z" + env: + TZ: "{{ tz }}" + RADARR__APP__LAUNCHBROWSER: false + RADARR__APP__INSTANCENAME: "{{ RADARR__APP__INSTANCENAME | default('Radarr') }}" + RADARR__AUTH__METHOD: "{{ RADARR__AUTH__METHOD | default('Forms') }}" + RADARR__AUTH__APIKEY: "{{ RADARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" + RADARR__AUTH__ENABLED: "{{ RADARR__AUTH__ENABLED | default(true) }}" + RADARR__AUTH__REQUIRED: "{{ RADARR__AUTH__REQUIRED | default('DisabledForLocalAddresses') }}" + RADARR__SERVER__ENABLESSL: "{{ RADARR__SERVER__ENABLESSL | default(false) }}" + RADARR__SERVER__PORT: "{{ RADARR__SERVER__PORT | default('7878') }}" + RADARR__SERVER__BINDADDRESS: "{{ RADARR__SERVER__BINDADDRESS | default('*') }}" + RADARR__LOG__ANALYTICSENABLED: "{{ RADARR__LOG__ANALYTICSENABLED | default(false) }}" + RADARR__LOG__LEVEL: "{{ RADARR__LOG__LEVEL | default('info') }}" + RADARR__UPDATE__AUTOMATICALLY: "{{ RADARR__UPDATE__AUTOMATICALLY | default(false) }}" + command: ["/app/Radarr", "--nobrowser", "--data=/config"] + restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/radarr/quadlets.yml b/roles/quadlets/radarr/quadlets.yml deleted file mode 100644 index 887cd40..0000000 --- a/roles/quadlets/radarr/quadlets.yml +++ /dev/null @@ -1,46 +0,0 @@ - -- name: radarr - type: build - image: localhost/radarr:latest - pull: missing - format: oci - force_rm: true - container_file: | - FROM {{ alpine_base_image }} - LABEL maintainer="{{ maintainer }}" - RUN apk add --no-cache \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ - icu-libs libintl sqlite-libs curl libmediainfo xmlstarlet jq \ - && url=$(curl -sL "https://api.github.com/repos/Radarr/Radarr/releases/latest" \ - | jq -r '.assets[] | select(.name | test("linux-musl-core-x64.tar.gz$")) | .browser_download_url') \ - && curl -L -o /tmp/radarr.tar.gz "$url" \ - && mkdir -p /app \ - && tar -xzf /tmp/radarr.tar.gz --strip-components=1 -C /app \ - && chmod +x /app/Radarr \ - && rm -rf /app/Radarr.Update - WORKDIR /app - -- name: radarr - type: container - image: localhost/radarr:latest - volumes: - - "{{ config_root }}/radarr:/config:Z" - - "{{ download_root }}/htpc:/downloads:z" - - "{{ media_root }}/movies:/movies:Z" - env: - TZ: "{{ tz }}" - RADARR__APP__LAUNCHBROWSER: false - RADARR__APP__INSTANCENAME: "{{ RADARR__APP__INSTANCENAME | default('Radarr') }}" - RADARR__AUTH__METHOD: "{{ RADARR__AUTH__METHOD | default('Forms') }}" - RADARR__AUTH__APIKEY: "{{ RADARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" - RADARR__AUTH__ENABLED: "{{ RADARR__AUTH__ENABLED | default(true) }}" - RADARR__AUTH__REQUIRED: "{{ RADARR__AUTH__REQUIRED | default('DisabledForLocalAddresses') }}" - RADARR__SERVER__ENABLESSL: "{{ RADARR__SERVER__ENABLESSL | default(false) }}" - RADARR__SERVER__PORT: "{{ RADARR__SERVER__PORT | default('7878') }}" - RADARR__SERVER__BINDADDRESS: "{{ RADARR__SERVER__BINDADDRESS | default('*') }}" - RADARR__LOG__ANALYTICSENABLED: "{{ RADARR__LOG__ANALYTICSENABLED | default(false) }}" - RADARR__LOG__LEVEL: "{{ RADARR__LOG__LEVEL | default('info') }}" - RADARR__UPDATE__AUTOMATICALLY: "{{ RADARR__UPDATE__AUTOMATICALLY | default(false) }}" - command: ["/app/Radarr", "--nobrowser", "--data=/config"] - restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/sabnzbd.yml b/roles/quadlets/sabnzbd.yml new file mode 100644 index 0000000..87308d9 --- /dev/null +++ b/roles/quadlets/sabnzbd.yml @@ -0,0 +1,524 @@ +quadlets: + - name: sabnzbd + type: build + image: localhost/sabnzbd:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN \ + rm -rf /etc/apk/repositories \ + && apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + python3 py3-pip git unzip ca-certificates par2cmdline 7zip \ + && apk add --no-cache --virtual=.build-deps \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + autoconf automake build-base openssl-dev libffi-dev python3-dev \ + && apk add --no-cache -X '{{ alpine_mirror }}/v3.14/main' unrar \ + && git clone --depth 1 --branch master https://github.com/sabnzbd/sabnzbd /app \ + && python3 -m venv /venv \ + && . /venv/bin/activate \ + && pip install --no-cache-dir -r /app/requirements.txt \ + && apk del --purge .build-deps + + - name: sabnzbd + type: container + image: localhost/sabnzbd:latest + volumes: + - "{{ config_root }}/sabnzbd:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ monitor_root }}/nzbs:/nzbs:Z" + env: + TZ: "{{ tz }}" + command: + - "/venv/bin/python" + - "-OO" + - "/app/SABnzbd.py" + - "--config-file=/config/sabnzbd.ini" + - "--browser=0" + restart_policy: on-failure + +configs: + - path: "{{ config_root }}/sabnzbd/sabnzbd.ini" + template: | + __version__ = 19 + __encoding__ = utf-8 + + [misc] + username = {{ sabnzbd_username | default("admin") }} + password = {{ sabnzbd_password | default("admin") }} + host = {{ sabnzbd_host | default("::") }} + port = {{ sabnzbd_http_port | default("8081") }} + api_key = {{ sabnzbd_api_key }} + nzb_key = {{ sabnzbd_nzb_key }} + download_dir = {{ sabnzbd_download_dir | default("/downloads/incomplete/sabnzbd") }} + complete_dir = {{ sabnzbd_complete_dir | default("/downloads/complete") }} + dirscan_dir = {{ sabnzbd_dirscan_dir | default("/nzbs") }} + web_dir = Glitter + web_color = Night + inet_exposure = 4 + cleanup_list = sfv, m3u, nfo + unwanted_extensions = exe, com + ignore_samples = 1 + enable_all_par = 1 + new_nzb_on_failure = 1 + replace_dots = 1 + prospective_par_download = 1 + deobfuscate_final_filenames = 1 + direct_unpack = 1 + pause_on_pwrar = 2 + propagation_delay = 0 + top_only = 1 + pre_script = None + queue_complete = "" + queue_complete_pers = 0 + bandwidth_perc = 100 + refresh_rate = 1 + interface_settings = '{"dateFormat":"fromNow","extraQueueColumns":["category","age"],"extraHistoryColumns":["size"],"displayCompact":false,"displayFullWidth":false,"confirmDeleteQueue":true,"confirmDeleteHistory":true,"keyboardShortcuts":true}' + queue_limit = 30 + config_lock = 0 + sched_converted = 0 + notified_new_skin = 2 + direct_unpack_tested = 1 + check_new_rel = 1 + auto_browser = 0 + language = en + enable_https_verification = 1 + https_port = {{ sabnzbd_https_port | default("9090") }} + bandwidth_max = 60M + cache_limit = 1G + https_cert = {{ sabnzbd_https_cert | default("/config/admin/server.cert") }} + https_key = {{ sabnzbd_https_key | default("/config/admin/server.key") }} + https_chain = "" + enable_https = {{ sabnzbd_enable_https | default(false) | int }} + permissions = "" + download_free = "" + complete_free = "" + fulldisk_autoresume = 0 + script_dir = "" + nzb_backup_dir = "" + admin_dir = admin + dirscan_speed = 5 + password_file = "" + log_dir = logs + max_art_tries = 3 + load_balancing = 2 + sfv_check = 1 + quick_check_ext_ignore = nfo, sfv, srr + script_can_fail = 0 + enable_recursive = 1 + flat_unpack = 0 + par_option = "" + pre_check = 0 + nice = "" + win_process_prio = 3 + ionice = "" + fail_hopeless_jobs = 1 + fast_fail = 1 + auto_disconnect = 1 + no_dupes = 0 + no_series_dupes = 0 + series_propercheck = 1 + auto_sort = "" + direct_unpack_threads = 3 + folder_rename = 1 + replace_spaces = 0 + safe_postproc = 1 + pause_on_post_processing = 0 + sanitize_safe = 0 + action_on_unwanted_extensions = 0 + unwanted_extensions_mode = 0 + history_retention = "" + enable_meta = 1 + quota_size = "" + quota_day = "" + quota_resume = 0 + quota_period = m + rating_enable = 0 + rating_host = "" + rating_api_key = "" + rating_filter_enable = 0 + rating_filter_abort_audio = 0 + rating_filter_abort_video = 0 + rating_filter_abort_encrypted = 0 + rating_filter_abort_encrypted_confirm = 0 + rating_filter_abort_spam = 0 + rating_filter_abort_spam_confirm = 0 + rating_filter_abort_downvoted = 0 + rating_filter_abort_keywords = "" + rating_filter_pause_audio = 0 + rating_filter_pause_video = 0 + rating_filter_pause_encrypted = 0 + rating_filter_pause_encrypted_confirm = 0 + rating_filter_pause_spam = 0 + rating_filter_pause_spam_confirm = 0 + rating_filter_pause_downvoted = 0 + rating_filter_pause_keywords = "" + enable_tv_sorting = 0 + tv_sort_string = "" + tv_categories = tv, + enable_movie_sorting = 0 + movie_sort_string = "" + movie_sort_extra = -cd%1 + movie_extra_folder = 0 + movie_categories = movies, + enable_date_sorting = 0 + date_sort_string = "" + date_categories = tv, + schedlines = , + rss_rate = 60 + ampm = 0 + replace_illegal = 1 + start_paused = 0 + preserve_paused_state = 0 + enable_par_cleanup = 1 + process_unpacked_par2 = 1 + enable_unrar = 1 + enable_unzip = 1 + enable_7zip = 1 + enable_filejoin = 1 + enable_tsjoin = 1 + overwrite_files = 0 + ignore_unrar_dates = 0 + backup_for_duplicates = 1 + empty_postproc = 0 + wait_for_dfolder = 0 + rss_filenames = 0 + api_logging = 1 + html_login = 1 + osx_menu = 1 + osx_speed = 1 + warn_dupl_jobs = 1 + helpful_warnings = 1 + keep_awake = 1 + win_menu = 1 + allow_incomplete_nzb = 0 + enable_broadcast = 1 + ipv6_hosting = 0 + fixed_ports = 1 + api_warnings = 1 + disable_api_key = 0 + no_penalties = 0 + x_frame_options = 1 + allow_old_ssl_tls = 0 + num_decoders = 3 + rss_odd_titles = nzbindex.nl/, nzbindex.com/, nzbclub.com/ + req_completion_rate = 100.2 + selftest_host = self-test.sabnzbd.org + movie_rename_limit = 100M + episode_rename_limit = 20M + size_limit = 0 + show_sysload = 2 + history_limit = 20 + wait_ext_drive = 5 + max_foldername_length = 246 + nomedia_marker = "" + ipv6_servers = 1 + url_base = /sabnzbd + host_whitelist = htpc, + local_ranges = , + max_url_retries = 10 + downloader_sleep_time = 10 + ssdp_broadcast_interval = 15 + socks5_proxy_url = "" + email_server = "" + email_to = , + email_from = "" + email_account = "" + email_pwd = "" + email_endjob = 0 + email_full = 0 + email_dir = "" + email_rss = 0 + email_cats = *, + num_simd_decoders = 2 + ext_rename_ignore = , + sorters_converted = 1 + backup_dir = "" + replace_underscores = 0 + tray_icon = 1 + enable_season_sorting = 1 + receive_threads = 2 + switchinterval = 0.005 + end_queue_script = None + no_smart_dupes = 0 + dupes_propercheck = 1 + history_retention_option = all + history_retention_number = 1 + enable_multipar = 1 + disable_archive = 0 + ipv6_staging = 0 + verify_xff_header = 0 + config_conversion_version = 4 + disable_par2cmdline = 0 + unrar_parameters = "" + outgoing_nntp_ip = "" + + [categories] + [[*]] + name = * + order = 0 + pp = 3 + script = None + dir = "" + newzbin = "" + priority = 0 + [[music]] + name = music + order = 0 + pp = "" + script = Default + dir = music + newzbin = music + priority = -100 + [[tv]] + name = tv + order = 0 + pp = "" + script = Default + dir = tv + newzbin = tv + priority = -100 + [[movies]] + name = movies + order = 0 + pp = "" + script = Default + dir = movies + newzbin = "movies, movie" + priority = -100 + [[radarr]] + name = radarr + order = 0 + pp = "" + script = Default + dir = radarr + newzbin = "movies, movie" + priority = -100 + [[sonarr]] + name = sonarr + order = 0 + pp = "" + script = Default + dir = sonarr + newzbin = tv + priority = -100 + [[other]] + name = other + order = 1 + pp = "" + script = Default + dir = other + newzbin = "games, game, other" + priority = -100 + [[lidarr]] + name = lidarr + order = 2 + pp = "" + script = Default + dir = lidarr + newzbin = music + priority = -100 + [[readarr]] + name = readarr + order = 3 + pp = "" + script = Default + dir = readarr + newzbin = ebooks + priority = -100 + [[lazylibrarian]] + name = lazylibrarian + order = 4 + pp = "" + script = Default + dir = lazylibrarian + newzbin = "ebooks, audiobooks" + priority = -100 + + [servers] + {% for s in sabnzbd_servers | default([]) %} + [[{{ s.name }}]] + name = {{ s.name }} + displayname = {{ s.displayname | default(s.name) }} + host = {{ s.host | default(s.name) }} + port = {{ s.port | default(563) }} + timeout = {{ s.timeout | default(60) }} + username = {{ s.username| default('') }} + password = {{ s.password| default('') }} + connections = {{ s.connections | default(50) }} + ssl = {{ s.ssl | default(1) }} + ssl_verify = {{ s.ssl_verify | default(1) }} + ssl_ciphers = {{ s.ssl_ciphers | default('""') }} + enable = {{ s.enable| default(1) }} + required = {{ s.required| default(0) }} + optional = {{ s.optional| default(0) }} + retention = {{ s.retention | default(0) }} + expire_date = {{ s.expire_date | default('""') }} + quota = {{ s.quota | default('""') }} + usage_at_start = {{ s.usage_at_start | default(0) }} + priority = {{ s.priority| default(0) }} + notes = {{ s.notes | default('""') }} + + {% endfor %} + [logging] + log_level = 1 + max_log_size = 5242880 + log_backups = 5 + [ncenter] + ncenter_enable = 0 + ncenter_cats = *, + ncenter_prio_startup = 1 + ncenter_prio_download = 0 + ncenter_prio_pause_resume = 0 + ncenter_prio_pp = 0 + ncenter_prio_complete = 1 + ncenter_prio_failed = 1 + ncenter_prio_disk_full = 1 + ncenter_prio_new_login = 0 + ncenter_prio_warning = 0 + ncenter_prio_error = 0 + ncenter_prio_queue_done = 1 + ncenter_prio_other = 1 + ncenter_prio_quota = 1 + [acenter] + acenter_enable = 0 + acenter_cats = *, + acenter_prio_startup = 0 + acenter_prio_download = 0 + acenter_prio_pause_resume = 0 + acenter_prio_pp = 0 + acenter_prio_complete = 1 + acenter_prio_failed = 1 + acenter_prio_disk_full = 1 + acenter_prio_new_login = 0 + acenter_prio_warning = 0 + acenter_prio_error = 0 + acenter_prio_queue_done = 1 + acenter_prio_other = 1 + acenter_prio_quota = 1 + [ntfosd] + ntfosd_enable = 1 + ntfosd_cats = *, + ntfosd_prio_startup = 1 + ntfosd_prio_download = 0 + ntfosd_prio_pause_resume = 0 + ntfosd_prio_pp = 0 + ntfosd_prio_complete = 1 + ntfosd_prio_failed = 1 + ntfosd_prio_disk_full = 1 + ntfosd_prio_new_login = 0 + ntfosd_prio_warning = 0 + ntfosd_prio_error = 0 + ntfosd_prio_queue_done = 1 + ntfosd_prio_other = 1 + ntfosd_prio_quota = 1 + [prowl] + prowl_enable = 0 + prowl_cats = *, + prowl_apikey = "" + prowl_prio_startup = -3 + prowl_prio_download = -3 + prowl_prio_pause_resume = -3 + prowl_prio_pp = -3 + prowl_prio_complete = 0 + prowl_prio_failed = 1 + prowl_prio_disk_full = 1 + prowl_prio_new_login = -3 + prowl_prio_warning = -3 + prowl_prio_error = -3 + prowl_prio_queue_done = 0 + prowl_prio_other = 0 + prowl_prio_quota = 0 + [pushover] + pushover_token = "" + pushover_userkey = "" + pushover_device = "" + pushover_emergency_expire = 3600 + pushover_emergency_retry = 60 + pushover_enable = 0 + pushover_cats = *, + pushover_prio_startup = -3 + pushover_prio_download = -2 + pushover_prio_pause_resume = -2 + pushover_prio_pp = -3 + pushover_prio_complete = -1 + pushover_prio_failed = -1 + pushover_prio_disk_full = 1 + pushover_prio_new_login = -3 + pushover_prio_warning = 1 + pushover_prio_error = 1 + pushover_prio_queue_done = -1 + pushover_prio_other = -1 + pushover_prio_quota = -1 + [pushbullet] + pushbullet_enable = 0 + pushbullet_cats = *, + pushbullet_apikey = "" + pushbullet_device = "" + pushbullet_prio_startup = 0 + pushbullet_prio_download = 0 + pushbullet_prio_pause_resume = 0 + pushbullet_prio_pp = 0 + pushbullet_prio_complete = 1 + pushbullet_prio_failed = 1 + pushbullet_prio_disk_full = 1 + pushbullet_prio_new_login = 0 + pushbullet_prio_warning = 0 + pushbullet_prio_error = 0 + pushbullet_prio_queue_done = 0 + pushbullet_prio_other = 1 + pushbullet_prio_quota = 1 + [nscript] + nscript_enable = 0 + nscript_cats = *, + nscript_script = "" + nscript_parameters = "" + nscript_prio_startup = 1 + nscript_prio_download = 0 + nscript_prio_pause_resume = 0 + nscript_prio_pp = 0 + nscript_prio_complete = 1 + nscript_prio_failed = 1 + nscript_prio_disk_full = 1 + nscript_prio_new_login = 0 + nscript_prio_warning = 0 + nscript_prio_error = 0 + nscript_prio_queue_done = 1 + nscript_prio_other = 1 + nscript_prio_quota = 1 + [apprise] + apprise_enable = 0 + apprise_cats = *, + apprise_urls = "" + apprise_target_startup = "" + apprise_target_startup_enable = 0 + apprise_target_download = "" + apprise_target_download_enable = 0 + apprise_target_pause_resume = "" + apprise_target_pause_resume_enable = 0 + apprise_target_pp = "" + apprise_target_pp_enable = 0 + apprise_target_complete = "" + apprise_target_complete_enable = 1 + apprise_target_failed = "" + apprise_target_failed_enable = 1 + apprise_target_disk_full = "" + apprise_target_disk_full_enable = 0 + apprise_target_new_login = "" + apprise_target_new_login_enable = 1 + apprise_target_warning = "" + apprise_target_warning_enable = 0 + apprise_target_error = "" + apprise_target_error_enable = 0 + apprise_target_queue_done = "" + apprise_target_queue_done_enable = 0 + apprise_target_other = "" + apprise_target_other_enable = 1 + apprise_target_quota = "" + apprise_target_quota_enable = 1 + diff --git a/roles/quadlets/sabnzbd/quadlets.yml b/roles/quadlets/sabnzbd/quadlets.yml deleted file mode 100644 index 6ca871a..0000000 --- a/roles/quadlets/sabnzbd/quadlets.yml +++ /dev/null @@ -1,42 +0,0 @@ -- name: sabnzbd - type: build - image: localhost/sabnzbd:latest - pull: missing - format: oci - force_rm: true - container_file: | - FROM {{ alpine_base_image }} - LABEL maintainer="{{ maintainer }}" - RUN \ - rm -rf /etc/apk/repositories \ - && apk add --no-cache \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ - python3 py3-pip git unzip ca-certificates par2cmdline 7zip \ - && apk add --no-cache --virtual=.build-deps \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ - autoconf automake build-base openssl-dev libffi-dev python3-dev \ - && apk add --no-cache -X '{{ alpine_mirror }}/v3.14/main' unrar \ - && git clone --depth 1 --branch master https://github.com/sabnzbd/sabnzbd /app \ - && python3 -m venv /venv \ - && . /venv/bin/activate \ - && pip install --no-cache-dir -r /app/requirements.txt \ - && apk del --purge .build-deps - -- name: sabnzbd - type: container - image: localhost/sabnzbd:latest - volumes: - - "{{ config_root }}/sabnzbd:/config:Z" - - "{{ download_root }}/htpc:/downloads:z" - - "{{ monitor_root }}/nzbs:/nzbs:Z" - env: - TZ: "{{ tz }}" - command: - - "/venv/bin/python" - - "-OO" - - "/app/SABnzbd.py" - - "--config-file=/config/sabnzbd.ini" - - "--browser=0" - restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/sabnzbd/sabnzbd.ini.j2 b/roles/quadlets/sabnzbd/sabnzbd.ini.j2 deleted file mode 100644 index a485d95..0000000 --- a/roles/quadlets/sabnzbd/sabnzbd.ini.j2 +++ /dev/null @@ -1,477 +0,0 @@ -__version__ = 19 -__encoding__ = utf-8 - -[misc] -username = {{ sabnzbd_username | default("admin") }} -password = {{ sabnzbd_password | default("admin") }} -host = {{ sabnzbd_host | default("::") }} -port = {{ sabnzbd_http_port | default("8081") }} -api_key = {{ sabnzbd_api_key }} -nzb_key = {{ sabnzbd_nzb_key }} -download_dir = {{ sabnzbd_download_dir | default("/downloads/incomplete/sabnzbd") }} -complete_dir = {{ sabnzbd_complete_dir | default("/downloads/complete") }} -dirscan_dir = {{ sabnzbd_dirscan_dir | default("/nzbs") }} -web_dir = Glitter -web_color = Night -inet_exposure = 4 -cleanup_list = sfv, m3u, nfo -unwanted_extensions = exe, com -ignore_samples = 1 -enable_all_par = 1 -new_nzb_on_failure = 1 -replace_dots = 1 -prospective_par_download = 1 -deobfuscate_final_filenames = 1 -direct_unpack = 1 -pause_on_pwrar = 2 -propagation_delay = 0 -top_only = 1 -pre_script = None -queue_complete = "" -queue_complete_pers = 0 -bandwidth_perc = 100 -refresh_rate = 1 -interface_settings = '{"dateFormat":"fromNow","extraQueueColumns":["category","age"],"extraHistoryColumns":["size"],"displayCompact":false,"displayFullWidth":false,"confirmDeleteQueue":true,"confirmDeleteHistory":true,"keyboardShortcuts":true}' -queue_limit = 30 -config_lock = 0 -sched_converted = 0 -notified_new_skin = 2 -direct_unpack_tested = 1 -check_new_rel = 1 -auto_browser = 0 -language = en -enable_https_verification = 1 -https_port = {{ sabnzbd_https_port | default("9090") }} -bandwidth_max = 60M -cache_limit = 1G -https_cert = {{ sabnzbd_https_cert | default("/config/admin/server.cert") }} -https_key = {{ sabnzbd_https_key | default("/config/admin/server.key") }} -https_chain = "" -enable_https = {{ sabnzbd_enable_https | default(false) | int }} -permissions = "" -download_free = "" -complete_free = "" -fulldisk_autoresume = 0 -script_dir = "" -nzb_backup_dir = "" -admin_dir = admin -dirscan_speed = 5 -password_file = "" -log_dir = logs -max_art_tries = 3 -load_balancing = 2 -sfv_check = 1 -quick_check_ext_ignore = nfo, sfv, srr -script_can_fail = 0 -enable_recursive = 1 -flat_unpack = 0 -par_option = "" -pre_check = 0 -nice = "" -win_process_prio = 3 -ionice = "" -fail_hopeless_jobs = 1 -fast_fail = 1 -auto_disconnect = 1 -no_dupes = 0 -no_series_dupes = 0 -series_propercheck = 1 -auto_sort = "" -direct_unpack_threads = 3 -folder_rename = 1 -replace_spaces = 0 -safe_postproc = 1 -pause_on_post_processing = 0 -sanitize_safe = 0 -action_on_unwanted_extensions = 0 -unwanted_extensions_mode = 0 -history_retention = "" -enable_meta = 1 -quota_size = "" -quota_day = "" -quota_resume = 0 -quota_period = m -rating_enable = 0 -rating_host = "" -rating_api_key = "" -rating_filter_enable = 0 -rating_filter_abort_audio = 0 -rating_filter_abort_video = 0 -rating_filter_abort_encrypted = 0 -rating_filter_abort_encrypted_confirm = 0 -rating_filter_abort_spam = 0 -rating_filter_abort_spam_confirm = 0 -rating_filter_abort_downvoted = 0 -rating_filter_abort_keywords = "" -rating_filter_pause_audio = 0 -rating_filter_pause_video = 0 -rating_filter_pause_encrypted = 0 -rating_filter_pause_encrypted_confirm = 0 -rating_filter_pause_spam = 0 -rating_filter_pause_spam_confirm = 0 -rating_filter_pause_downvoted = 0 -rating_filter_pause_keywords = "" -enable_tv_sorting = 0 -tv_sort_string = "" -tv_categories = tv, -enable_movie_sorting = 0 -movie_sort_string = "" -movie_sort_extra = -cd%1 -movie_extra_folder = 0 -movie_categories = movies, -enable_date_sorting = 0 -date_sort_string = "" -date_categories = tv, -schedlines = , -rss_rate = 60 -ampm = 0 -replace_illegal = 1 -start_paused = 0 -preserve_paused_state = 0 -enable_par_cleanup = 1 -process_unpacked_par2 = 1 -enable_unrar = 1 -enable_unzip = 1 -enable_7zip = 1 -enable_filejoin = 1 -enable_tsjoin = 1 -overwrite_files = 0 -ignore_unrar_dates = 0 -backup_for_duplicates = 1 -empty_postproc = 0 -wait_for_dfolder = 0 -rss_filenames = 0 -api_logging = 1 -html_login = 1 -osx_menu = 1 -osx_speed = 1 -warn_dupl_jobs = 1 -helpful_warnings = 1 -keep_awake = 1 -win_menu = 1 -allow_incomplete_nzb = 0 -enable_broadcast = 1 -ipv6_hosting = 0 -fixed_ports = 1 -api_warnings = 1 -disable_api_key = 0 -no_penalties = 0 -x_frame_options = 1 -allow_old_ssl_tls = 0 -num_decoders = 3 -rss_odd_titles = nzbindex.nl/, nzbindex.com/, nzbclub.com/ -req_completion_rate = 100.2 -selftest_host = self-test.sabnzbd.org -movie_rename_limit = 100M -episode_rename_limit = 20M -size_limit = 0 -show_sysload = 2 -history_limit = 20 -wait_ext_drive = 5 -max_foldername_length = 246 -nomedia_marker = "" -ipv6_servers = 1 -url_base = /sabnzbd -host_whitelist = htpc, -local_ranges = , -max_url_retries = 10 -downloader_sleep_time = 10 -ssdp_broadcast_interval = 15 -socks5_proxy_url = "" -email_server = "" -email_to = , -email_from = "" -email_account = "" -email_pwd = "" -email_endjob = 0 -email_full = 0 -email_dir = "" -email_rss = 0 -email_cats = *, -num_simd_decoders = 2 -ext_rename_ignore = , -sorters_converted = 1 -backup_dir = "" -replace_underscores = 0 -tray_icon = 1 -enable_season_sorting = 1 -receive_threads = 2 -switchinterval = 0.005 -end_queue_script = None -no_smart_dupes = 0 -dupes_propercheck = 1 -history_retention_option = all -history_retention_number = 1 -enable_multipar = 1 -disable_archive = 0 -ipv6_staging = 0 -verify_xff_header = 0 -config_conversion_version = 4 -disable_par2cmdline = 0 -unrar_parameters = "" -outgoing_nntp_ip = "" - -[categories] -[[*]] -name = * -order = 0 -pp = 3 -script = None -dir = "" -newzbin = "" -priority = 0 -[[music]] -name = music -order = 0 -pp = "" -script = Default -dir = music -newzbin = music -priority = -100 -[[tv]] -name = tv -order = 0 -pp = "" -script = Default -dir = tv -newzbin = tv -priority = -100 -[[movies]] -name = movies -order = 0 -pp = "" -script = Default -dir = movies -newzbin = "movies, movie" -priority = -100 -[[radarr]] -name = radarr -order = 0 -pp = "" -script = Default -dir = radarr -newzbin = "movies, movie" -priority = -100 -[[sonarr]] -name = sonarr -order = 0 -pp = "" -script = Default -dir = sonarr -newzbin = tv -priority = -100 -[[other]] -name = other -order = 1 -pp = "" -script = Default -dir = other -newzbin = "games, game, other" -priority = -100 -[[lidarr]] -name = lidarr -order = 2 -pp = "" -script = Default -dir = lidarr -newzbin = music -priority = -100 -[[readarr]] -name = readarr -order = 3 -pp = "" -script = Default -dir = readarr -newzbin = ebooks -priority = -100 -[[lazylibrarian]] -name = lazylibrarian -order = 4 -pp = "" -script = Default -dir = lazylibrarian -newzbin = "ebooks, audiobooks" -priority = -100 - -[servers] -{% for s in sabnzbd_servers | default([]) %} -[[{{ s.name }}]] -name = {{ s.name }} -displayname = {{ s.displayname | default(s.name) }} -host = {{ s.host | default(s.name) }} -port = {{ s.port | default(563) }} -timeout = {{ s.timeout | default(60) }} -username = {{ s.username| default('') }} -password = {{ s.password| default('') }} -connections = {{ s.connections | default(50) }} -ssl = {{ s.ssl | default(1) }} -ssl_verify = {{ s.ssl_verify | default(1) }} -ssl_ciphers = {{ s.ssl_ciphers | default('""') }} -enable = {{ s.enable| default(1) }} -required = {{ s.required| default(0) }} -optional = {{ s.optional| default(0) }} -retention = {{ s.retention | default(0) }} -expire_date = {{ s.expire_date | default('""') }} -quota = {{ s.quota | default('""') }} -usage_at_start = {{ s.usage_at_start | default(0) }} -priority = {{ s.priority| default(0) }} -notes = {{ s.notes | default('""') }} - -{% endfor %} -[logging] -log_level = 1 -max_log_size = 5242880 -log_backups = 5 -[ncenter] -ncenter_enable = 0 -ncenter_cats = *, -ncenter_prio_startup = 1 -ncenter_prio_download = 0 -ncenter_prio_pause_resume = 0 -ncenter_prio_pp = 0 -ncenter_prio_complete = 1 -ncenter_prio_failed = 1 -ncenter_prio_disk_full = 1 -ncenter_prio_new_login = 0 -ncenter_prio_warning = 0 -ncenter_prio_error = 0 -ncenter_prio_queue_done = 1 -ncenter_prio_other = 1 -ncenter_prio_quota = 1 -[acenter] -acenter_enable = 0 -acenter_cats = *, -acenter_prio_startup = 0 -acenter_prio_download = 0 -acenter_prio_pause_resume = 0 -acenter_prio_pp = 0 -acenter_prio_complete = 1 -acenter_prio_failed = 1 -acenter_prio_disk_full = 1 -acenter_prio_new_login = 0 -acenter_prio_warning = 0 -acenter_prio_error = 0 -acenter_prio_queue_done = 1 -acenter_prio_other = 1 -acenter_prio_quota = 1 -[ntfosd] -ntfosd_enable = 1 -ntfosd_cats = *, -ntfosd_prio_startup = 1 -ntfosd_prio_download = 0 -ntfosd_prio_pause_resume = 0 -ntfosd_prio_pp = 0 -ntfosd_prio_complete = 1 -ntfosd_prio_failed = 1 -ntfosd_prio_disk_full = 1 -ntfosd_prio_new_login = 0 -ntfosd_prio_warning = 0 -ntfosd_prio_error = 0 -ntfosd_prio_queue_done = 1 -ntfosd_prio_other = 1 -ntfosd_prio_quota = 1 -[prowl] -prowl_enable = 0 -prowl_cats = *, -prowl_apikey = "" -prowl_prio_startup = -3 -prowl_prio_download = -3 -prowl_prio_pause_resume = -3 -prowl_prio_pp = -3 -prowl_prio_complete = 0 -prowl_prio_failed = 1 -prowl_prio_disk_full = 1 -prowl_prio_new_login = -3 -prowl_prio_warning = -3 -prowl_prio_error = -3 -prowl_prio_queue_done = 0 -prowl_prio_other = 0 -prowl_prio_quota = 0 -[pushover] -pushover_token = "" -pushover_userkey = "" -pushover_device = "" -pushover_emergency_expire = 3600 -pushover_emergency_retry = 60 -pushover_enable = 0 -pushover_cats = *, -pushover_prio_startup = -3 -pushover_prio_download = -2 -pushover_prio_pause_resume = -2 -pushover_prio_pp = -3 -pushover_prio_complete = -1 -pushover_prio_failed = -1 -pushover_prio_disk_full = 1 -pushover_prio_new_login = -3 -pushover_prio_warning = 1 -pushover_prio_error = 1 -pushover_prio_queue_done = -1 -pushover_prio_other = -1 -pushover_prio_quota = -1 -[pushbullet] -pushbullet_enable = 0 -pushbullet_cats = *, -pushbullet_apikey = "" -pushbullet_device = "" -pushbullet_prio_startup = 0 -pushbullet_prio_download = 0 -pushbullet_prio_pause_resume = 0 -pushbullet_prio_pp = 0 -pushbullet_prio_complete = 1 -pushbullet_prio_failed = 1 -pushbullet_prio_disk_full = 1 -pushbullet_prio_new_login = 0 -pushbullet_prio_warning = 0 -pushbullet_prio_error = 0 -pushbullet_prio_queue_done = 0 -pushbullet_prio_other = 1 -pushbullet_prio_quota = 1 -[nscript] -nscript_enable = 0 -nscript_cats = *, -nscript_script = "" -nscript_parameters = "" -nscript_prio_startup = 1 -nscript_prio_download = 0 -nscript_prio_pause_resume = 0 -nscript_prio_pp = 0 -nscript_prio_complete = 1 -nscript_prio_failed = 1 -nscript_prio_disk_full = 1 -nscript_prio_new_login = 0 -nscript_prio_warning = 0 -nscript_prio_error = 0 -nscript_prio_queue_done = 1 -nscript_prio_other = 1 -nscript_prio_quota = 1 -[apprise] -apprise_enable = 0 -apprise_cats = *, -apprise_urls = "" -apprise_target_startup = "" -apprise_target_startup_enable = 0 -apprise_target_download = "" -apprise_target_download_enable = 0 -apprise_target_pause_resume = "" -apprise_target_pause_resume_enable = 0 -apprise_target_pp = "" -apprise_target_pp_enable = 0 -apprise_target_complete = "" -apprise_target_complete_enable = 1 -apprise_target_failed = "" -apprise_target_failed_enable = 1 -apprise_target_disk_full = "" -apprise_target_disk_full_enable = 0 -apprise_target_new_login = "" -apprise_target_new_login_enable = 1 -apprise_target_warning = "" -apprise_target_warning_enable = 0 -apprise_target_error = "" -apprise_target_error_enable = 0 -apprise_target_queue_done = "" -apprise_target_queue_done_enable = 0 -apprise_target_other = "" -apprise_target_other_enable = 1 -apprise_target_quota = "" -apprise_target_quota_enable = 1 - diff --git a/roles/quadlets/sonarr.yml b/roles/quadlets/sonarr.yml new file mode 100644 index 0000000..fecf7ce --- /dev/null +++ b/roles/quadlets/sonarr.yml @@ -0,0 +1,44 @@ + quadlets: + - name: sonarr + type: build + image: localhost/sonarr:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + libintl sqlite-libs icu-libs curl jq \ + && url=$(curl -sL "https://api.github.com/repos/Sonarr/Sonarr/releases/latest" \ + | jq -r '.assets[] | select(.name | test("linux-musl-x64.tar.gz$")) | .browser_download_url') \ + && curl -L -o /tmp/Sonarr.tar.gz "$url" \ + && mkdir -p /app && tar -xzf /tmp/Sonarr.tar.gz -C /app --strip-components=1 + WORKDIR /app + + - name: sonarr + type: container + image: localhost/sonarr:latest + volumes: + - "{{ config_root }}/sonarr:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ media_root }}/tv:/tv:Z" + env: + TZ: "{{ tz }}" + SONARR__APP__LAUNCHBROWSER: false + SONARR__APP__INSTANCENAME: "{{ SONARR__APP__INSTANCENAME | default('Sonarr') }}" + SONARR__AUTH__METHOD: "{{ SONARR__AUTH__METHOD | default('Forms') }}" + SONARR__AUTH__APIKEY: "{{ SONARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" + SONARR__SERVER__ENABLESSL: "{{ SONARR__SERVER__ENABLESSL | default(false) }}" + SONARR__SERVER__SSLPORT: "{{ SONARR__SERVER__SSLPORT | default('9898') }}" + SONARR__SERVER__PORT: "{{ SONARR__SERVER__PORT | default('8989') }}" + SONARR__SERVER__BINDADDRESS: "{{ SONARR__SERVER__BINDADDRESS | default('*') }}" + SONARR__SERVER__SSLCERTPATH: "{{ SONARR__SERVER__SSLCERTPATH | default('/config/ssl/server.crt') }}" + SONARR__SERVER__SSLCERTPASSWORD: "{{ SONARR__SERVER__SSLCERTPASSWORD | default('/config/ssl/server.key') }}" + SONARR__LOG__ANALYTICSENABLED: "{{ SONARR__LOG__ANALYTICSENABLED | default(false) }}" + SONARR__UPDATE__AUTOMATICALLY: "{{ SONARR__UPDATE__AUTOMATICALLY | default(false) }}" + SONARR__LOG__LEVEL: "{{ SONARR__LOG__LEVEL | default('info') }}" + command: ["/app/Sonarr", "-data=/config"] + restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/sonarr/quadlets.yml b/roles/quadlets/sonarr/quadlets.yml deleted file mode 100644 index 13bd36a..0000000 --- a/roles/quadlets/sonarr/quadlets.yml +++ /dev/null @@ -1,43 +0,0 @@ -- name: sonarr - type: build - image: localhost/sonarr:latest - pull: missing - format: oci - force_rm: true - container_file: | - FROM {{ alpine_base_image }} - LABEL maintainer="{{ maintainer }}" - RUN apk add --no-cache \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ - libintl sqlite-libs icu-libs curl jq \ - && url=$(curl -sL "https://api.github.com/repos/Sonarr/Sonarr/releases/latest" \ - | jq -r '.assets[] | select(.name | test("linux-musl-x64.tar.gz$")) | .browser_download_url') \ - && curl -L -o /tmp/Sonarr.tar.gz "$url" \ - && mkdir -p /app && tar -xzf /tmp/Sonarr.tar.gz -C /app --strip-components=1 - WORKDIR /app - -- name: sonarr - type: container - image: localhost/sonarr:latest - volumes: - - "{{ config_root }}/sonarr:/config:Z" - - "{{ download_root }}/htpc:/downloads:z" - - "{{ media_root }}/tv:/tv:Z" - env: - TZ: "{{ tz }}" - SONARR__APP__LAUNCHBROWSER: false - SONARR__APP__INSTANCENAME: "{{ SONARR__APP__INSTANCENAME | default('Sonarr') }}" - SONARR__AUTH__METHOD: "{{ SONARR__AUTH__METHOD | default('Forms') }}" - SONARR__AUTH__APIKEY: "{{ SONARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" - SONARR__SERVER__ENABLESSL: "{{ SONARR__SERVER__ENABLESSL | default(false) }}" - SONARR__SERVER__SSLPORT: "{{ SONARR__SERVER__SSLPORT | default('9898') }}" - SONARR__SERVER__PORT: "{{ SONARR__SERVER__PORT | default('8989') }}" - SONARR__SERVER__BINDADDRESS: "{{ SONARR__SERVER__BINDADDRESS | default('*') }}" - SONARR__SERVER__SSLCERTPATH: "{{ SONARR__SERVER__SSLCERTPATH | default('/config/ssl/server.crt') }}" - SONARR__SERVER__SSLCERTPASSWORD: "{{ SONARR__SERVER__SSLCERTPASSWORD | default('/config/ssl/server.key') }}" - SONARR__LOG__ANALYTICSENABLED: "{{ SONARR__LOG__ANALYTICSENABLED | default(false) }}" - SONARR__UPDATE__AUTOMATICALLY: "{{ SONARR__UPDATE__AUTOMATICALLY | default(false) }}" - SONARR__LOG__LEVEL: "{{ SONARR__LOG__LEVEL | default('info') }}" - command: ["/app/Sonarr", "-data=/config"] - restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/tasks/main.yml b/roles/quadlets/tasks/main.yml index 80d0bc9..0a20eb7 100644 --- a/roles/quadlets/tasks/main.yml +++ b/roles/quadlets/tasks/main.yml @@ -1,22 +1,29 @@ --- -- name: Deploy quadlet app configs - ansible.builtin.include_tasks: ../../deploy_files.yml +- name: Load all quadlet app definitions + ansible.builtin.set_fact: + quadlets_apps: "{{ quadlets_apps | default([]) + [lookup('file', item.path) | from_yaml] }}" + loop: "{{ lookup('ansible.builtin.find', role_path, patterns='*.yml', excludes='quadlets.yml').files }}" + +- name: Deploy app configs from metadata + ansible.builtin.template: + content: "{{ item.1.template }}" + dest: "{{ target_root }}/{{ item.1.path }}" + mode: '0644' + loop: "{{ quadlets_apps | subelements('configs', skip_missing=True) }}" vars: - var_prefix: quadlets - subdir: '' - target_root: "{{ ansible_facts.env.HOME }}/.config" - use_symlinks: false - become_root: false - when: quadlets_deploy_configs | default(false) + is_root_config: "{{ item.0.metadata.user | default('home') in ['service', 'root'] }}" + target_root: "{{ is_root_config | ternary('', ansible_facts.env.HOME) }}" + become: "{{ is_root_config }}" + when: item.1.template is defined - name: Initialize quadlet specs ansible.builtin.set_fact: quadlets_all_specs: [] -- name: Load all quadlet definitions +- name: Extract quadlet specs from app definitions ansible.builtin.set_fact: - quadlets_all_specs: "{{ quadlets_all_specs + (lookup('file', item.path) | from_yaml) }}" - loop: "{{ lookup('ansible.builtin.find', role_path, patterns='quadlets.yml', recurse=yes).files }}" + quadlets_all_specs: "{{ quadlets_all_specs + item.1 }}" + loop: "{{ quadlets_apps | subelements('quadlets', skip_missing=True) }}" - name: Build final quadlet specs with pod injection ansible.builtin.set_fact: diff --git a/roles/quadlets/traefik.yml b/roles/quadlets/traefik.yml new file mode 100644 index 0000000..339f8b2 --- /dev/null +++ b/roles/quadlets/traefik.yml @@ -0,0 +1,73 @@ +quadlets: + - name: traefik + type: container + image: docker.io/traefik:latest + pull: newer + volumes: + - "{{ config_root }}/traefik:/etc/traefik:Z" + env: + TZ: "{{ tz }}" + command: + - "--api.dashboard=true" + - "--api.insecure=true" + - "--providers.file.directory=/etc/traefik/dynamic" + - "--providers.file.watch=true" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--entrypoints.websecure.http.tls.certFile=/etc/traefik/server.crt" + - "--entrypoints.websecure.http.tls.keyFile=/etc/traefik/server.key" + - "--log.level=INFO" + restart_policy: on-failure + +configs: + - path: "{{ config_root }}/traefik/server.crt" + template: {{ traefik_server_cert }} + - path: "{{ config_root }}/traefik/server.key" + template: {{ traefik_server_key }} + - path: "{{ config_root }}/traefik/dynamic/dynamic.yml" + template: | + --- + http: + middlewares: + redirect-https: + redirectScheme: + scheme: https + permanent: true + + routers: + redirect-to-https: + rule: "HostRegexp(`{any:.*}`)" + entryPoints: + - web + middlewares: + - redirect-https + service: noop + + {% for app_name in traefik_enabled_apps %} + {{ app_name }}: + rule: "PathPrefix(`/{{ app_name }}`)" + service: {{ app_name }} + entryPoints: + - websecure + tls: {} + {% endfor %} + + dashboard: + rule: "PathPrefix(`/dashboard`)" + service: api@internal + entryPoints: + - websecure + tls: {} + + services: + noop: + loadBalancer: + servers: + - url: "http://localhost" + + {% for app_name in traefik_enabled_apps %} + {{ app_name }}: + loadBalancer: + servers: + - url: "http://localhost:{{ lookup('vars', app_name).port }}" + {% endfor %} \ No newline at end of file diff --git a/roles/quadlets/traefik/dynamic/htpc.yml.j2 b/roles/quadlets/traefik/dynamic/htpc.yml.j2 deleted file mode 100644 index 83946d1..0000000 --- a/roles/quadlets/traefik/dynamic/htpc.yml.j2 +++ /dev/null @@ -1,116 +0,0 @@ ---- -# Traefik dynamic configuration for HTPC services -# Auto-generated by Ansible - deployed as dotfile - -http: - middlewares: - redirect-https: - redirectScheme: - scheme: https - permanent: true - - routers: - redirect-to-https: - rule: "HostRegexp(`{any:.*}`)" - entryPoints: - - web - middlewares: - - redirect-https - service: noop - - sabnzbd: - rule: "PathPrefix(`/sabnzbd`)" - service: sabnzbd - entryPoints: - - websecure - tls: {} - - qbittorrent: - rule: "PathPrefix(`/qbittorrent`)" - service: qbittorrent - entryPoints: - - websecure - tls: {} - - sonarr: - rule: "PathPrefix(`/sonarr`)" - service: sonarr - entryPoints: - - websecure - tls: {} - - radarr: - rule: "PathPrefix(`/radarr`)" - service: radarr - entryPoints: - - websecure - tls: {} - - lidarr: - rule: "PathPrefix(`/lidarr`)" - service: lidarr - entryPoints: - - websecure - tls: {} - - lazylibrarian: - rule: "PathPrefix(`/lazylibrarian`)" - service: lazylibrarian - entryPoints: - - websecure - tls: {} - - prowlarr: - rule: "PathPrefix(`/prowlarr`)" - service: prowlarr - entryPoints: - - websecure - tls: {} - - dashboard: - rule: "PathPrefix(`/dashboard`)" - service: api@internal - entryPoints: - - websecure - tls: {} - - services: - noop: - loadBalancer: - servers: - - url: "http://localhost" - - sabnzbd: - loadBalancer: - servers: - - url: "http://localhost:8081" - - qbittorrent: - loadBalancer: - servers: - - url: "http://localhost:8082" - - sonarr: - loadBalancer: - servers: - - url: "http://localhost:{{ SONARR__SERVER__PORT | default('8989') }}" - - radarr: - loadBalancer: - servers: - - url: "http://localhost:{{ RADARR__SERVER__PORT | default('7878') }}" - - lidarr: - loadBalancer: - servers: - - url: "http://localhost:{{ LIDARR__SERVER__PORT | default('8686') }}" - - lazylibrarian: - loadBalancer: - servers: - - url: "http://localhost:{{ lazylibrarian_port | default('5299') }}" - - prowlarr: - loadBalancer: - servers: - - url: "http://localhost:{{ PROWLARR__SERVER__PORT | default('9696') }}" diff --git a/roles/quadlets/traefik/quadlets.yml b/roles/quadlets/traefik/quadlets.yml deleted file mode 100644 index 3fd9bbf..0000000 --- a/roles/quadlets/traefik/quadlets.yml +++ /dev/null @@ -1,19 +0,0 @@ -- name: traefik - type: container - image: docker.io/traefik:latest - pull: newer - volumes: - - "{{ config_root }}/traefik:/etc/traefik:Z" - env: - TZ: "{{ tz }}" - command: - - "--api.dashboard=true" - - "--api.insecure=true" - - "--providers.file.directory=/etc/traefik/dynamic" - - "--providers.file.watch=true" - - "--entrypoints.web.address=:80" - - "--entrypoints.websecure.address=:443" - - "--entrypoints.websecure.http.tls.certFile=/etc/traefik/server.crt" - - "--entrypoints.websecure.http.tls.keyFile=/etc/traefik/server.key" - - "--log.level=INFO" - restart_policy: on-failure \ No newline at end of file diff --git a/roles/quadlets/traefik/server.crt.j2 b/roles/quadlets/traefik/server.crt.j2 deleted file mode 100644 index 13edda5..0000000 --- a/roles/quadlets/traefik/server.crt.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ traefik_server_cert }} \ No newline at end of file diff --git a/roles/quadlets/traefik/server.key.j2 b/roles/quadlets/traefik/server.key.j2 deleted file mode 100644 index a9b66fe..0000000 --- a/roles/quadlets/traefik/server.key.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ traefik_server_key }} \ No newline at end of file diff --git a/roles/quadlets/unpackerr.yml b/roles/quadlets/unpackerr.yml new file mode 100644 index 0000000..25b91e5 --- /dev/null +++ b/roles/quadlets/unpackerr.yml @@ -0,0 +1,37 @@ +quadlets: + - name: unpackerr + type: build + image: localhost/unpackerr:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + curl tar jq \ + && url=$(curl -sL "https://api.github.com/repos/davidnewhall/Unpackerr/releases/latest" \ + | jq -r '.assets[] | select(.name == "unpackerr.amd64.linux.gz") | .browser_download_url') \ + && [ -n "$url" ] \ + && curl -L -o /tmp/unpackerr.gz "$url" \ + && mkdir -p /app \ + && gunzip -c /tmp/unpackerr.gz > /app/unpackerr \ + && chmod +x /app/unpackerr \ + && rm /tmp/unpackerr.gz + WORKDIR /app + + - name: unpackerr + type: container + image: localhost/unpackerr:latest + volumes: + - "{{ config_root }}/unpackerr:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + env: + TZ: "{{ tz }}" + UNPACKERR__LOG__ANALYTICSENABLED: "{{ UNPACKERR__LOG__ANALYTICSENABLED | default(false) }}" + UNPACKERR__UPDATE__AUTOMATICALLY: "{{ UNPACKERR__UPDATE__AUTOMATICALLY | default(false) }}" + UNPACKERR__LOG__LEVEL: "{{ UNPACKERR__LOG__LEVEL | default('info') }}" + command: ["/app/unpackerr"] + restart_policy: on-failure diff --git a/roles/quadlets/unpackerr/quadlets.yml b/roles/quadlets/unpackerr/quadlets.yml deleted file mode 100644 index b360a43..0000000 --- a/roles/quadlets/unpackerr/quadlets.yml +++ /dev/null @@ -1,36 +0,0 @@ -- name: unpackerr - type: build - image: localhost/unpackerr:latest - pull: missing - format: oci - force_rm: true - container_file: | - FROM {{ alpine_base_image }} - LABEL maintainer="{{ maintainer }}" - RUN apk add --no-cache \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ - -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ - curl tar jq \ - && url=$(curl -sL "https://api.github.com/repos/davidnewhall/Unpackerr/releases/latest" \ - | jq -r '.assets[] | select(.name == "unpackerr.amd64.linux.gz") | .browser_download_url') \ - && [ -n "$url" ] \ - && curl -L -o /tmp/unpackerr.gz "$url" \ - && mkdir -p /app \ - && gunzip -c /tmp/unpackerr.gz > /app/unpackerr \ - && chmod +x /app/unpackerr \ - && rm /tmp/unpackerr.gz - WORKDIR /app - -- name: unpackerr - type: container - image: localhost/unpackerr:latest - volumes: - - "{{ config_root }}/unpackerr:/config:Z" - - "{{ download_root }}/htpc:/downloads:z" - env: - TZ: "{{ tz }}" - UNPACKERR__LOG__ANALYTICSENABLED: "{{ UNPACKERR__LOG__ANALYTICSENABLED | default(false) }}" - UNPACKERR__UPDATE__AUTOMATICALLY: "{{ UNPACKERR__UPDATE__AUTOMATICALLY | default(false) }}" - UNPACKERR__LOG__LEVEL: "{{ UNPACKERR__LOG__LEVEL | default('info') }}" - command: ["/app/unpackerr"] - restart_policy: on-failure diff --git a/roles/scripts/tasks/main.yml b/roles/scripts/tasks/main.yml index 52d9fb6..8517710 100644 --- a/roles/scripts/tasks/main.yml +++ b/roles/scripts/tasks/main.yml @@ -1,10 +1,30 @@ --- +- name: Glob all files in role directory + ansible.builtin.find: + paths: "{{ role_path }}" + depth: 1 + file_type: file + register: scripts_files -- name: Deploy scripts to user's local bin - ansible.builtin.include_tasks: ../../deploy_files.yml - vars: - var_prefix: scripts - subdir: '' - target_root: "{{ ansible_facts.env.HOME }}/.local/bin" - use_symlinks: true - become_root: false +- name: "Ensure script directory exist" + ansible.builtin.file: + path: "{{ ansible_facts.env.HOME }}/.local/bin" + state: directory + mode: "0755" + +- name: "Deploy scripts (local with symlinks)" + ansible.builtin.file: + src: "{{ item.path }}" + dest: "{{ ansible_facts.env.HOME }}/.local/bin/{{ item.path | basename }}" + state: link + force: true + loop: "{{ scripts_files.files }}" + when: ansible_connection in ['local', 'localhost'] + +- name: "Deploy scripts (remote with copy)" + ansible.builtin.copy: + src: "{{ item.path }}" + dest: "{{ ansible_facts.env.HOME }}/.local/bin/{{ item.path | basename }}" + mode: '0755' + loop: "{{ scripts_files.files }}" + when: ansible_connection not in ['local', 'localhost'] diff --git a/roles/scripts/tmux-management b/roles/scripts/tmux-management index 8b2e3ae..7c0b2e6 100755 --- a/roles/scripts/tmux-management +++ b/roles/scripts/tmux-management @@ -1,11 +1,20 @@ #!/usr/bin/env bash # Open a tiled tmux window with one pane per host each in its own tmux session. # The local session is always the last (active) pane. - set -euo pipefail +# Accept hostnames from command-line arguments +if (( $# > 0 )); then + HOSTS=("$@") +else + # Default hostnames in the desired pane order + HOSTS=( + workstation + laptop + ) +fi + # Configuration (override with env vars if desired) -HOSTS=(workstation laptop) # hosts in pane order REMOTE_SESSION=${REMOTE_SESSION:-main} # tmux session on remotes SYNCHRONIZE=${SYNCHRONIZE:-1} # 1 = broadcast keystrokes INCLUDE_LOCAL=${INCLUDE_LOCAL:-1} # 0 = skip local host @@ -56,7 +65,8 @@ open_cmd() { printf 'tmux -L %q new -A -s %q' "${SESSION}_local" "$REMOTE_SESSION" fi else - printf 'ssh -t %q tmux new -A -s %q' "$tgt" "$REMOTE_SESSION" + # SSH with keepalive settings for faster broken pipe detection + printf 'ssh -o ServerAliveInterval=20 -o ServerAliveCountMax=3 -t %q tmux new -A -s %q' "$tgt" "$REMOTE_SESSION" fi } @@ -74,8 +84,8 @@ tmux select-layout -t "$SESSION:0" tiled # Keep panes visible when commands exit tmux set-option -t "$SESSION:0" remain-on-exit on -# Auto-respawn any pane whose command dies -tmux set-hook -t "$SESSION" pane-died "run-shell 'tmux respawn-pane -k -t #{pane_id}'" +# Reconnect dead panes when user focuses on them +tmux set-hook -t "$SESSION" pane-focus-in "if -F '#{pane_dead}' 'respawn-pane -k -t #{pane_id}'" # Activate the last pane (local host) local_index=$(( ${#TARGETS[@]} - 1 )) diff --git a/roles/services/tasks/main.yml b/roles/services/tasks/main.yml deleted file mode 100644 index 80e3221..0000000 --- a/roles/services/tasks/main.yml +++ /dev/null @@ -1,34 +0,0 @@ ---- -- name: Enable and start system services - ansible.builtin.systemd: - name: "{{ item }}" - enabled: true - state: started - scope: system - loop: "{{ (services_system_enabled | default([])) + (services_system_enabled_group | default([])) }}" - become: true - -- name: Disable and stop system services - ansible.builtin.systemd: - name: "{{ item }}" - enabled: false - state: stopped - scope: system - loop: "{{ (services_system_disabled | default([])) + (services_system_disabled_group | default([])) }}" - become: true - -- name: Enable and start user services - ansible.builtin.systemd: - name: "{{ item }}" - enabled: true - state: started - scope: user - loop: "{{ (services_user_enabled | default([])) + (services_user_enabled_group | default([])) }}" - -- name: Disable and stop user services - ansible.builtin.systemd: - name: "{{ item }}" - enabled: false - state: stopped - scope: system - loop: "{{ (services_user_disabled | default([])) + (services_user_disabled_group | default([])) }}"