diff --git a/group_vars/laptop/dotfiles.yml b/group_vars/laptop/dotfiles.yml new file mode 100644 index 0000000..587ad08 --- /dev/null +++ b/group_vars/laptop/dotfiles.yml @@ -0,0 +1,19 @@ +--- +# 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/workstation/dotfiles.yml b/group_vars/workstation/dotfiles.yml new file mode 100644 index 0000000..2c640de --- /dev/null +++ b/group_vars/workstation/dotfiles.yml @@ -0,0 +1,19 @@ +--- +# 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 a0b9760..4597193 100644 --- a/group_vars/workstation/quadlets.yml +++ b/group_vars/workstation/quadlets.yml @@ -2,7 +2,6 @@ debug: false # set to true to print debug info log_level: "info" -rebuild: true # rebuild images quadlets_deploy_configs: true # deploy quadlet service configs maintainer: "Bryan C. Roessler" @@ -12,8 +11,6 @@ alpine_mirror: "https://mirror.pilotfiber.com/alpinelinux" # Directories config_root: "{{ lookup('env', 'HOME') }}/.config" -quadlet_root: "{{ lookup('env', 'HOME') }}/.config/containers/systemd" -backup_root: "{{ lookup('env', 'HOME') }}/.config/containers/systemd/backup" download_root: "{{ lookup('env', 'HOME') }}/downloads" monitor_root: "{{ lookup('env', 'HOME') }}/downloads" media_root: "{{ lookup('env', 'HOME') }}/media" @@ -33,350 +30,19 @@ podman_prune_images: true podman_pull_image: false podman_continue_if_pull_fails: false -podman_quadlet_specs: - - # Pods +# Pod definitions +pods: - name: htpc - type: pod network: pasta publish: - "8080:80" - "8443:443" - - # Build images - - name: htpc_sabnzbd - type: build - image: localhost/htpc_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: htpc_qbittorrent - type: build - image: localhost/htpc_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: htpc_sonarr - type: build - image: localhost/htpc_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: htpc_radarr - type: build - image: localhost/htpc_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: htpc_lidarr - type: build - image: localhost/htpc_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: htpc_prowlarr - type: build - image: localhost/htpc_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: htpc_unpackerr - type: build - image: localhost/htpc_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 - - # Containers - - name: htpc_traefik - type: container - pod: htpc - 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 - - - name: htpc_sabnzbd - type: container - pod: htpc - image: localhost/htpc_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 - - - name: htpc_qbittorrent - type: container - pod: htpc - image: localhost/htpc_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 - - - name: htpc_sonarr - type: container - pod: htpc - image: localhost/htpc_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 - - - name: htpc_radarr - type: container - pod: htpc - image: localhost/htpc_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 - - - name: htpc_lidarr - type: container - pod: htpc - image: localhost/htpc_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 - - - name: htpc_lazylibrarian - type: container - pod: htpc - image: localhost/htpc_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 - - - name: htpc_prowlarr - type: container - pod: htpc - image: localhost/htpc_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 - - - name: htpc_unpackerr - type: container - pod: htpc - image: localhost/htpc_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 + containers: + - sabnzbd + - qbittorrent + - sonarr + - radarr + - lidarr + - prowlarr + - unpackerr + - traefik diff --git a/roles/deploy_files.yml b/roles/deploy_files.yml index 1dcf6f9..3d0dfe6 100644 --- a/roles/deploy_files.yml +++ b/roles/deploy_files.yml @@ -9,11 +9,9 @@ - name: "Build file lists for {{ var_prefix }}" ansible.builtin.set_fact: "{{ var_prefix }}_files": "{{ lookup('community.general.filetree', - role_path ~ '/common/' ~ (subdir | default('')), - role_path ~ '/' ~ group_names[0] ~ '/' ~ (subdir | default(''))) | selectattr('state', 'equalto', 'file') | rejectattr('path', 'match', '.*\\.j2$') | list }}" + role_path ~ '/' ~ (subdir | default(''))) | selectattr('state', 'equalto', 'file') | rejectattr('path', 'match', '.*\\.j2$') | list }}" "{{ var_prefix }}_templates": "{{ lookup('community.general.filetree', - role_path ~ '/common/' ~ (subdir | default('')), - role_path ~ '/' ~ group_names[0] ~ '/' ~ (subdir | default(''))) | selectattr('state', 'equalto', 'file') | selectattr('path', 'match', '.*\\.j2$') | list }}" + role_path ~ '/' ~ (subdir | default(''))) | selectattr('state', 'equalto', 'file') | selectattr('path', 'match', '.*\\.j2$') | list }}" - name: "Ensure directories exist for {{ var_prefix }}" ansible.builtin.file: diff --git a/roles/dotfiles/common/home/.config/aichat/config.yaml.j2 b/roles/dotfiles/home/aichat/.config/aichat/config.yaml.j2 similarity index 100% rename from roles/dotfiles/common/home/.config/aichat/config.yaml.j2 rename to roles/dotfiles/home/aichat/.config/aichat/config.yaml.j2 diff --git a/roles/dotfiles/workstation/home/.config/btrbk/btrbk.conf b/roles/dotfiles/home/btrbk-ws/.config/btrbk/btrbk.conf similarity index 100% rename from roles/dotfiles/workstation/home/.config/btrbk/btrbk.conf rename to roles/dotfiles/home/btrbk-ws/.config/btrbk/btrbk.conf diff --git a/roles/dotfiles/laptop/home/.config/btrbk/btrbk.conf b/roles/dotfiles/home/btrbk/.config/btrbk/btrbk.conf similarity index 100% rename from roles/dotfiles/laptop/home/.config/btrbk/btrbk.conf rename to roles/dotfiles/home/btrbk/.config/btrbk/btrbk.conf diff --git a/roles/dotfiles/common/home/.env.j2 b/roles/dotfiles/home/env/.env.j2 similarity index 100% rename from roles/dotfiles/common/home/.env.j2 rename to roles/dotfiles/home/env/.env.j2 diff --git a/roles/dotfiles/common/home/.gitconfig b/roles/dotfiles/home/git/.gitconfig similarity index 100% rename from roles/dotfiles/common/home/.gitconfig rename to roles/dotfiles/home/git/.gitconfig diff --git a/roles/dotfiles/common/home/.local/share/nautilus/scripts/share-link b/roles/dotfiles/home/nautilus/.local/share/nautilus/scripts/share-link similarity index 100% rename from roles/dotfiles/common/home/.local/share/nautilus/scripts/share-link rename to roles/dotfiles/home/nautilus/.local/share/nautilus/scripts/share-link diff --git a/roles/dotfiles/common/home/.ssh/authorized_keys.j2 b/roles/dotfiles/home/ssh/.ssh/authorized_keys.j2 similarity index 100% rename from roles/dotfiles/common/home/.ssh/authorized_keys.j2 rename to roles/dotfiles/home/ssh/.ssh/authorized_keys.j2 diff --git a/roles/dotfiles/common/home/.ssh/config b/roles/dotfiles/home/ssh/.ssh/config similarity index 100% rename from roles/dotfiles/common/home/.ssh/config rename to roles/dotfiles/home/ssh/.ssh/config diff --git a/roles/dotfiles/common/home/.tmux.conf b/roles/dotfiles/home/tmux/.tmux.conf similarity index 100% rename from roles/dotfiles/common/home/.tmux.conf rename to roles/dotfiles/home/tmux/.tmux.conf diff --git a/roles/dotfiles/common/home/.vimrc b/roles/dotfiles/home/vim/.vimrc similarity index 100% rename from roles/dotfiles/common/home/.vimrc rename to roles/dotfiles/home/vim/.vimrc diff --git a/roles/dotfiles/common/home/.x2goclient/sessions b/roles/dotfiles/home/x2go/.x2goclient/sessions similarity index 100% rename from roles/dotfiles/common/home/.x2goclient/sessions rename to roles/dotfiles/home/x2go/.x2goclient/sessions diff --git a/roles/dotfiles/common/home/.zshrc b/roles/dotfiles/home/zsh/.zshrc similarity index 100% rename from roles/dotfiles/common/home/.zshrc rename to roles/dotfiles/home/zsh/.zshrc diff --git a/roles/dotfiles/common/root/etc/dnf/dnf.conf b/roles/dotfiles/root/dnf/etc/dnf/dnf.conf similarity index 100% rename from roles/dotfiles/common/root/etc/dnf/dnf.conf rename to roles/dotfiles/root/dnf/etc/dnf/dnf.conf diff --git a/roles/dotfiles/laptop/root/etc/keyd/default.conf b/roles/dotfiles/root/keyd/etc/keyd/default.conf similarity index 100% rename from roles/dotfiles/laptop/root/etc/keyd/default.conf rename to roles/dotfiles/root/keyd/etc/keyd/default.conf diff --git a/roles/dotfiles/workstation/root/etc/pwrstatd.conf b/roles/dotfiles/root/pwrstatd/etc/pwrstatd.conf similarity index 100% rename from roles/dotfiles/workstation/root/etc/pwrstatd.conf rename to roles/dotfiles/root/pwrstatd/etc/pwrstatd.conf diff --git a/roles/dotfiles/common/root/etc/sysconfig/btrfsmaintenance b/roles/dotfiles/root/sysconfig/etc/sysconfig/btrfsmaintenance similarity index 100% rename from roles/dotfiles/common/root/etc/sysconfig/btrfsmaintenance rename to roles/dotfiles/root/sysconfig/etc/sysconfig/btrfsmaintenance diff --git a/roles/dotfiles/tasks/main.yml b/roles/dotfiles/tasks/main.yml index 4a81cf4..34dc6c7 100644 --- a/roles/dotfiles/tasks/main.yml +++ b/roles/dotfiles/tasks/main.yml @@ -1,18 +1,20 @@ --- -- name: Deploy home dotfiles +- name: Deploy selected home dotfile packages ansible.builtin.include_tasks: ../../deploy_files.yml vars: var_prefix: dotfiles_home - subdir: home + subdir: "home/{{ item }}" target_root: "{{ ansible_facts.env.HOME }}" use_symlinks: true become_root: false + loop: "{{ dotfiles_home_packages | default([]) }}" -- name: Deploy root dotfiles +- name: Deploy selected root dotfile packages ansible.builtin.include_tasks: ../../deploy_files.yml vars: var_prefix: dotfiles_root - subdir: root + subdir: "root/{{ item }}" target_root: "/" use_symlinks: true become_root: true + loop: "{{ dotfiles_root_packages | default([]) }}" diff --git a/roles/quadlets/README.md b/roles/quadlets/README.md new file mode 100644 index 0000000..473a0f4 diff --git a/roles/quadlets/lazylibrarian/config.ini.j2 b/roles/quadlets/lazylibrarian/config.ini.j2 new file mode 100644 index 0000000..7b47715 --- /dev/null +++ b/roles/quadlets/lazylibrarian/config.ini.j2 @@ -0,0 +1,129 @@ +[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 new file mode 100644 index 0000000..0437c0e --- /dev/null +++ b/roles/quadlets/lazylibrarian/quadlets.yml @@ -0,0 +1,11 @@ +- 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/quadlets.yml b/roles/quadlets/lidarr/quadlets.yml new file mode 100644 index 0000000..53f0c8d --- /dev/null +++ b/roles/quadlets/lidarr/quadlets.yml @@ -0,0 +1,48 @@ +- 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/quadlets.yml b/roles/quadlets/prowlarr/quadlets.yml new file mode 100644 index 0000000..f5b3e57 --- /dev/null +++ b/roles/quadlets/prowlarr/quadlets.yml @@ -0,0 +1,44 @@ +- 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/qBittorrent/config/qBittorrent.conf.j2 b/roles/quadlets/qbittorrent/qBittorrent/config/qBittorrent.conf.j2 new file mode 100644 index 0000000..5d1c598 --- /dev/null +++ b/roles/quadlets/qbittorrent/qBittorrent/config/qBittorrent.conf.j2 @@ -0,0 +1,127 @@ +[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 new file mode 100644 index 0000000..a065fb0 --- /dev/null +++ b/roles/quadlets/qbittorrent/quadlets.yml @@ -0,0 +1,30 @@ +- 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/quadlets.yml b/roles/quadlets/radarr/quadlets.yml new file mode 100644 index 0000000..887cd40 --- /dev/null +++ b/roles/quadlets/radarr/quadlets.yml @@ -0,0 +1,46 @@ + +- 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/quadlets.yml b/roles/quadlets/sabnzbd/quadlets.yml new file mode 100644 index 0000000..6ca871a --- /dev/null +++ b/roles/quadlets/sabnzbd/quadlets.yml @@ -0,0 +1,42 @@ +- 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 new file mode 100644 index 0000000..a485d95 --- /dev/null +++ b/roles/quadlets/sabnzbd/sabnzbd.ini.j2 @@ -0,0 +1,477 @@ +__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/quadlets.yml b/roles/quadlets/sonarr/quadlets.yml new file mode 100644 index 0000000..13bd36a --- /dev/null +++ b/roles/quadlets/sonarr/quadlets.yml @@ -0,0 +1,43 @@ +- 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 new file mode 100644 index 0000000..cfa4387 --- /dev/null +++ b/roles/quadlets/tasks/main.yml @@ -0,0 +1,46 @@ +--- +- name: Deploy quadlet app configs + ansible.builtin.include_tasks: ../../deploy_files.yml + vars: + var_prefix: quadlets + subdir: '' + target_root: "{{ ansible_facts.env.HOME }}/.config" + use_symlinks: false + become_root: false + when: quadlets_deploy_configs | default(false) + +- name: Initialize quadlet specs + ansible.builtin.set_fact: + quadlets_all_specs: [] + +- name: Load all quadlet 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 }}" + +- name: Build final quadlet specs with pod injection + ansible.builtin.set_fact: + quadlets_specs: "{{ (pods | default([])) | map('combine', {'type': 'pod'}) | list }}" + +- name: Add containers to quadlet specs with pod injection + ansible.builtin.set_fact: + quadlets_specs: "{{ quadlets_specs + [container_spec[0] | combine({'pod': item.0.name})] }}" + loop: "{{ pods | default([]) | subelements('containers') }}" + vars: + container_spec: "{{ quadlets_all_specs | selectattr('name', 'equalto', item.1) | selectattr('type', 'equalto', 'container') | list }}" + when: container_spec | length > 0 + +- name: Add build specs for enabled containers + ansible.builtin.set_fact: + quadlets_specs: "{{ quadlets_specs + [item] }}" + loop: "{{ quadlets_all_specs }}" + when: + - item.type == 'build' + - item.name in (pods | default([]) | map(attribute='containers') | flatten) + +- name: Deploy quadlets using fedora.linux_system_roles.podman + ansible.builtin.include_role: + name: fedora.linux_system_roles.podman + vars: + podman_quadlet_specs: "{{ quadlets_specs }}" + when: quadlets_specs is defined and quadlets_specs | length > 0 diff --git a/roles/quadlets/traefik/dynamic/htpc.yml.j2 b/roles/quadlets/traefik/dynamic/htpc.yml.j2 new file mode 100644 index 0000000..83946d1 --- /dev/null +++ b/roles/quadlets/traefik/dynamic/htpc.yml.j2 @@ -0,0 +1,116 @@ +--- +# 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 new file mode 100644 index 0000000..3fd9bbf --- /dev/null +++ b/roles/quadlets/traefik/quadlets.yml @@ -0,0 +1,19 @@ +- 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 new file mode 100644 index 0000000..13edda5 --- /dev/null +++ b/roles/quadlets/traefik/server.crt.j2 @@ -0,0 +1 @@ +{{ 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 new file mode 100644 index 0000000..a9b66fe --- /dev/null +++ b/roles/quadlets/traefik/server.key.j2 @@ -0,0 +1 @@ +{{ traefik_server_key }} \ No newline at end of file diff --git a/roles/quadlets/unpackerr/quadlets.yml b/roles/quadlets/unpackerr/quadlets.yml new file mode 100644 index 0000000..b360a43 --- /dev/null +++ b/roles/quadlets/unpackerr/quadlets.yml @@ -0,0 +1,36 @@ +- 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/common/btrfs-convert b/roles/scripts/btrfs-convert similarity index 100% rename from roles/scripts/common/btrfs-convert rename to roles/scripts/btrfs-convert diff --git a/roles/scripts/common/chroot-rescue b/roles/scripts/chroot-rescue similarity index 100% rename from roles/scripts/common/chroot-rescue rename to roles/scripts/chroot-rescue diff --git a/roles/scripts/common/container-home-assistant b/roles/scripts/container-home-assistant similarity index 100% rename from roles/scripts/common/container-home-assistant rename to roles/scripts/container-home-assistant diff --git a/roles/scripts/common/drive-info b/roles/scripts/drive-info similarity index 100% rename from roles/scripts/common/drive-info rename to roles/scripts/drive-info diff --git a/roles/scripts/common/estimate-musicdir b/roles/scripts/estimate-musicdir similarity index 100% rename from roles/scripts/common/estimate-musicdir rename to roles/scripts/estimate-musicdir diff --git a/roles/scripts/common/extract b/roles/scripts/extract similarity index 100% rename from roles/scripts/common/extract rename to roles/scripts/extract diff --git a/roles/scripts/common/history-clean b/roles/scripts/history-clean similarity index 100% rename from roles/scripts/common/history-clean rename to roles/scripts/history-clean diff --git a/roles/scripts/common/iso-to-mkv b/roles/scripts/iso-to-mkv similarity index 100% rename from roles/scripts/common/iso-to-mkv rename to roles/scripts/iso-to-mkv diff --git a/roles/scripts/common/jriver-exclusions.ps1 b/roles/scripts/jriver-exclusions.ps1 similarity index 100% rename from roles/scripts/common/jriver-exclusions.ps1 rename to roles/scripts/jriver-exclusions.ps1 diff --git a/roles/scripts/common/jriver-expressions.txt b/roles/scripts/jriver-expressions.txt similarity index 100% rename from roles/scripts/common/jriver-expressions.txt rename to roles/scripts/jriver-expressions.txt diff --git a/roles/scripts/common/jriver-fix-date-imported b/roles/scripts/jriver-fix-date-imported similarity index 100% rename from roles/scripts/common/jriver-fix-date-imported rename to roles/scripts/jriver-fix-date-imported diff --git a/roles/scripts/common/jriver-replace-date-imported b/roles/scripts/jriver-replace-date-imported similarity index 100% rename from roles/scripts/common/jriver-replace-date-imported rename to roles/scripts/jriver-replace-date-imported diff --git a/roles/scripts/common/prune-files b/roles/scripts/prune-files similarity index 100% rename from roles/scripts/common/prune-files rename to roles/scripts/prune-files diff --git a/roles/scripts/common/random-words b/roles/scripts/random-words similarity index 100% rename from roles/scripts/common/random-words rename to roles/scripts/random-words diff --git a/roles/scripts/common/remove-small-dirs b/roles/scripts/remove-small-dirs similarity index 100% rename from roles/scripts/common/remove-small-dirs rename to roles/scripts/remove-small-dirs diff --git a/roles/scripts/common/speedtest-compare b/roles/scripts/speedtest-compare similarity index 100% rename from roles/scripts/common/speedtest-compare rename to roles/scripts/speedtest-compare diff --git a/roles/scripts/common/ssh-wrap b/roles/scripts/ssh-wrap similarity index 100% rename from roles/scripts/common/ssh-wrap rename to roles/scripts/ssh-wrap diff --git a/roles/scripts/common/strip-exif b/roles/scripts/strip-exif similarity index 100% rename from roles/scripts/common/strip-exif rename to roles/scripts/strip-exif diff --git a/roles/scripts/common/sync-music b/roles/scripts/sync-music similarity index 100% rename from roles/scripts/common/sync-music rename to roles/scripts/sync-music diff --git a/roles/scripts/common/tmux-management b/roles/scripts/tmux-management similarity index 100% rename from roles/scripts/common/tmux-management rename to roles/scripts/tmux-management diff --git a/roles/scripts/common/tree-to-markdown b/roles/scripts/tree-to-markdown similarity index 100% rename from roles/scripts/common/tree-to-markdown rename to roles/scripts/tree-to-markdown diff --git a/roles/scripts/common/update-git-hooks b/roles/scripts/update-git-hooks similarity index 100% rename from roles/scripts/common/update-git-hooks rename to roles/scripts/update-git-hooks