diff --git a/.gitignore b/.gitignore index 383de38..6cfd010 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,65 @@ vaultpass /.ansible /temp/ +# Created by https://www.toptal.com/developers/gitignore/api/-f,linux,markdown,ansible,terraform +# Edit at https://www.toptal.com/developers/gitignore?templates=-f,linux,markdown,ansible,terraform + +#!! ERROR: -f is undefined. Use list command to see defined gitignore types !!# + +### Ansible ### +*.retry + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +#!! ERROR: markdown is undefined. Use list command to see defined gitignore types !!# + +### Terraform ### +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +# End of https://www.toptal.com/developers/gitignore/api/-f,linux,markdown,ansible,terraform diff --git a/ansible.cfg b/ansible.cfg index 8734d30..25b7877 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -1,4 +1,11 @@ [defaults] remote_tmp = /tmp inventory = inventory + roles_path = .ansible/roles:roles +collections_path = .ansible/collections + +interpreter_python = auto_silent + +[ssh_connection] +pipelining = True diff --git a/roles/arr/templates/compose.yaml.jinja b/roles/arr/templates/compose.yaml.jinja index dde72e6..1caff10 100644 --- a/roles/arr/templates/compose.yaml.jinja +++ b/roles/arr/templates/compose.yaml.jinja @@ -1,7 +1,7 @@ services: sonarr: container_name: sonarr - image: lscr.io/linuxserver/sonarr:latest + image: "lscr.io/linuxserver/sonarr:{{ arrstack_sonarr_version }}" networks: - caddy environment: @@ -21,7 +21,7 @@ services: radarr: container_name: radarr - image: lscr.io/linuxserver/radarr:latest + image: "lscr.io/linuxserver/radarr:{{ arrstack_radarr_version }}" networks: - caddy environment: @@ -31,7 +31,7 @@ services: - UMASK_SET={{ arrstack_umask_set }} volumes: - "{{ arrstack_env_dir }}/config/radarr:/config" - - "/mnt/ext/data/media/movies:/data/media/movies" # FIXME: Find solution + - "/mnt/ext/data/media/movies:/data/media/movies" # FIXME: Find non-hardcoded solution - "{{ arrstack_serve_dir }}/files/usenet:/data/usenet" - "{{ arrstack_serve_dir }}/files/torrent:/data/torrent" restart: unless-stopped @@ -41,7 +41,7 @@ services: lidarr: container_name: lidarr - image: lscr.io/linuxserver/lidarr:latest + image: "lscr.io/linuxserver/lidarr:{{ arrstack_lidarr_version }}" networks: - caddy environment: @@ -66,7 +66,7 @@ services: readarr: container_name: readarr - image: lscr.io/linuxserver/readarr:develop + image: "lscr.io/linuxserver/readarr:{{ arrstack_readarr_version }}" networks: - caddy environment: @@ -86,7 +86,7 @@ services: prowlarr: container_name: prowlarr - image: lscr.io/linuxserver/prowlarr:develop + image: "lscr.io/linuxserver/prowlarr:{{ arrstack_prowlarr_version }}" networks: - caddy environment: @@ -102,7 +102,7 @@ services: caddy.reverse_proxy: "{{ '{{' }}upstreams 9696{{ '}}'}}" beets: - image: lscr.io/linuxserver/beets:latest + image: "lscr.io/linuxserver/beets:{{ arrstack_beets_version }}" container_name: beets networks: - caddy @@ -123,7 +123,7 @@ services: caddy.reverse_proxy: "{{ '{{' }}upstreams 8337{{ '}}'}}" tdarr: - image: ghcr.io/haveagitgat/tdarr + image: "ghcr.io/haveagitgat/tdarr:{{ arrstack_tdarr_version }}" container_name: tdarr networks: - caddy @@ -148,6 +148,7 @@ services: - "{{ arrstack_env_dir }}/data/tdarr:/app/server" - "{{ arrstack_serve_dir }}/media/tv:/media/tv" - "/mnt/ext/data/media/movies:/media/movies" # FIXME: To be changed? + - "/mnt/ext/data/media/fanedits:/media/fanedits" # FIXME: Find non-hardcoded solution - "/transcodes:/transcodes" # TODO: Implement dynamic form with variable? restart: unless-stopped devices: @@ -157,7 +158,7 @@ services: caddy.reverse_proxy: "{{ '{{' }}upstreams 8265{{ '}}'}}" bazarr: - image: lscr.io/linuxserver/bazarr:latest + image: "lscr.io/linuxserver/bazarr:{{ arrstack_bazarr_version }}" container_name: bazarr networks: - caddy @@ -169,6 +170,7 @@ services: - "{{ arrstack_env_dir }}/config/sabnzbd:/config" - "{{ arrstack_serve_dir }}/media/tv:/data/media/tv" - "/mnt/ext/data/media/movies:/data/media/movies" # FIXME: To be changed? + - "/mnt/ext/data/media/fanedits:/data/media/fanedits" # FIXME: Find non-hardcoded solution ports: - 6767:6767 restart: unless-stopped @@ -178,7 +180,7 @@ services: sabnzbd: container_name: sabnzbd - image: lscr.io/linuxserver/sabnzbd:latest + image: "lscr.io/linuxserver/sabnzbd:{{ arrstack_sabnzbd_version }}" networks: - caddy environment: @@ -196,7 +198,7 @@ services: vpn: container_name: vpn - image: qmcgaw/gluetun:v3 + image: "qmcgaw/gluetun:{{ arrstack_gluetun_version }}" networks: - caddy environment: @@ -230,7 +232,7 @@ services: caddy: "{{ arrstack_qbit_subdomain }}" caddy.reverse_proxy: "{{ '{{' }}upstreams 8888{{ '}}'}}" qbittorrent: - image: linuxserver/qbittorrent + image: "linuxserver/qbittorrent:{{ arrstack_qbittorrent_version }}" container_name: qbittorrent environment: - PUID={{ arrstack_puid }} @@ -248,7 +250,7 @@ services: restart: unless-stopped homarr: - image: ghcr.io/ajnart/homarr:latest + image: "ghcr.io/ajnart/homarr:{{ arrstack_homarr_version }}" container_name: homarr networks: - caddy @@ -263,7 +265,7 @@ services: caddy.reverse_proxy: "{{ '{{' }}upstreams 7575{{ '}}'}}" jellyseerr: - image: fallenbagel/jellyseerr:latest + image: "fallenbagel/jellyseerr:{{ arrstack_jellyseerr_version }}" container_name: jellyseerr networks: - caddy @@ -281,7 +283,7 @@ services: audiobookshelf: container_name: audiobookshelf - image: ghcr.io/advplyr/audiobookshelf:latest + image: "ghcr.io/advplyr/audiobookshelf:{{ arrstack_audiobookshelf_version }}" networks: - caddy environment: @@ -300,7 +302,7 @@ services: caddy.reverse_proxy: "{{ '{{' }}upstreams 80{{ '}}'}}" jellyfin: - image: lscr.io/linuxserver/jellyfin:latest + image: "lscr.io/linuxserver/jellyfin:{{ arrstack_jellyfin_version }}" container_name: jellyfin networks: - caddy @@ -320,6 +322,7 @@ services: - "{{ arrstack_env_dir }}/config/jellyfin:/config" - "{{ arrstack_env_dir }}/data/jellyfin:/config/data" - "/mnt/ext/data/media/movies:/media/movies" # FIXME: To be changed? + - "/mnt/ext/data/media/fanedits:/media/fanedits" # FIXME: Find non-hardcoded solution - "{{ arrstack_serve_dir }}/media/tv:/media/tv" - "{{ arrstack_serve_dir }}/media/music:/media/music" ports: # FIXME: how to enable discovery behind proxies? @@ -331,7 +334,7 @@ services: caddy.reverse_proxy: "{{ '{{' }}upstreams 8096{{ '}}'}}" gonic: - image: sentriz/gonic:latest + image: "sentriz/gonic:{{ arrstack_gonic_version }}" networks: - caddy environment: @@ -351,7 +354,7 @@ services: {% if restic_enable|d(False) == True and arrstack_restic_enable|d(False) == True %} backup: - image: mazzolino/restic + image: "mazzolino/restic:{{ arrstack_restic_version }}" hostname: "{{ ansible_hostname | default() }}" environment: TZ: "{{ restic_tz }}" diff --git a/roles/arr/vars/main.yaml b/roles/arr/vars/main.yaml index c17c9bb..8d382a0 100644 --- a/roles/arr/vars/main.yaml +++ b/roles/arr/vars/main.yaml @@ -1,2 +1,20 @@ --- -# vars file for arr + +arrstack_sonarr_version: latest +arrstack_radarr_version: latest +arrstack_lidarr_version: latest +arrstack_readarr_version: develop +arrstack_prowlarr_version: develop +arrstack_beets_version: latest +arrstack_tdarr_version: latest +arrstack_bazarr_version: latest +arrstack_sabnzbd_version: latest +arrstack_gluetun_version: v3 +arrstack_qbittorrent_version: latest +arrstack_homarr_version: latest +arrstack_jellyseerr_version: latest +arrstack_audiobookshelf_version: latest +arrstack_jellyfin_version: "10.11.3" +arrstack_gonic_version: latest + +arrstack_restic_version: latest # TODO: Should maybe be set in restic role instead? diff --git a/roles/infrastructure/tasks/main.yaml b/roles/infrastructure/tasks/main.yaml new file mode 100644 index 0000000..1169ce3 --- /dev/null +++ b/roles/infrastructure/tasks/main.yaml @@ -0,0 +1,26 @@ +--- +# role currently only works with opentofu +# Either manually extend to both or just leave out test? +- name: Check if tofu is installed + vars: + terraform_bin: tofu + ansible.builtin.command: + argv: + - which + - "{{ terraform_bin|quote }}" + check_mode: false # run even in check mode + tags: debug + register: tofu_installed + failed_when: false + changed_when: false + +- name: Run terraform + community.general.terraform: + binary_path: "{{ (tofu_installed.rc in [ 0 ]) | ternary('tofu', 'terraform') }}" + project_path: "tofu/" + state: present + register: output + +- name: Debug output + debug: + var: output diff --git a/roles/nfs/defaults/main.yaml b/roles/nfs/defaults/main.yaml index f8088e6..8accc81 100644 --- a/roles/nfs/defaults/main.yaml +++ b/roles/nfs/defaults/main.yaml @@ -4,3 +4,6 @@ nfs_export_lines: - "/srv/media 192.168.0.0/24(rw,async,no_subtree_check) 100.112.0.0/16(rw,async,no_subtree_check)" - "/srv/files 192.168.0.0/24(rw,async,no_subtree_check) 100.112.0.0/16(rw,async,no_subtree_check)" - "/mnt/ext/data/videos 192.168.0.0/24(rw,async,no_subtree_check) 100.112.0.0/16(rw,async,no_subtree_check)" + +nfs_v4_only: true +nfs_v4_disable_rpcbind_fallback: false # needed by Debian 13 diff --git a/roles/nfs/tasks/main.yaml b/roles/nfs/tasks/main.yaml index 165ea36..478a880 100644 --- a/roles/nfs/tasks/main.yaml +++ b/roles/nfs/tasks/main.yaml @@ -10,7 +10,7 @@ ansible.builtin.template: src: exports.jinja dest: /etc/exports - mode: '0644' + mode: "0644" become: true notify: Reload nfs service @@ -22,6 +22,10 @@ become: true loop: "{{ nfs_export_lines }}" +- name: Disable NFSv2/NFSv3 to leave NFSv4-only server + ansible.builtin.include_tasks: "nfs-v4-only.yaml" + when: "nfs_v4_only" + - name: Enable nfs server unit ansible.builtin.systemd: enabled: true diff --git a/roles/nfs/tasks/nfs-v4-only.yaml b/roles/nfs/tasks/nfs-v4-only.yaml new file mode 100644 index 0000000..5c6bf00 --- /dev/null +++ b/roles/nfs/tasks/nfs-v4-only.yaml @@ -0,0 +1,48 @@ +--- +- name: Configure /etc/default/nfs-common for NFSv4-only + ansible.builtin.lineinfile: + path: /etc/default/nfs-common + regexp: '^(# *)?{{ item.key }}=.*' + line: '{{ item.key }}={{ item.val }}' + loop: + - { key: NEED_STATD, val: '"no"' } + - { key: NEED_IDMAPD, val: '"yes"' } + become: true + notify: Reload nfs service + +- name: Configure /etc/default/nfs-kernel-server for NFSv4-only + ansible.builtin.lineinfile: + path: /etc/default/nfs-kernel-server + regexp: '^(# *)?{{ item.key }}=.*' + line: '{{ item.key }}={{ item.val }}' + create: true # in case the file or the var is missing + loop: + - { key: RPCNFSDOPTS, val: '"--no-nfs-version 2 --no-nfs-version 3"' } + - { key: RPCMOUNTDOPTS, val: '"--manage-gids --no-nfs-version 2 --no-nfs-version 3"' } + become: true + notify: Reload nfs service + + # This _can_ be used on very modern kernels, but disables + # the rpcbind fallback if nfsdctl lockd configuration fails. + # Debian 13 still requires this so it is disabled by default +- name: Mask rpcbind units (not needed for NFSv4) + ansible.builtin.systemd: + name: "{{ item }}" + masked: true + state: stopped + loop: + - rpcbind.service + - rpcbind.socket + become: true + when: "nfs_v4_disable_rpcbind_fallback" + +- name: Unmask rpcbind units to keep as fallback + ansible.builtin.systemd: + name: "{{ item }}" + masked: false + state: started + loop: + - rpcbind.socket + - rpcbind.service + become: true + when: "not nfs_v4_disable_rpcbind_fallback" diff --git a/site.yaml b/site.yaml index 0f89754..b77d574 100644 --- a/site.yaml +++ b/site.yaml @@ -5,7 +5,6 @@ gather_facts: False become: true tags: - - system - bootstrap tasks: - name: check for python @@ -50,6 +49,13 @@ # name: incus-install # tags: incus +- name: Raise infrastructure + hosts: localhost + tags: infrastructure + tasks: + - ansible.builtin.import_role: + name: infrastructure + # ansible-galaxy install geerlingguy.docker - name: Install docker hosts: instance_system diff --git a/tofu/main.tf b/tofu/main.tf new file mode 100644 index 0000000..ed46066 --- /dev/null +++ b/tofu/main.tf @@ -0,0 +1,5 @@ + +output "my_debug_output" { + description = "just debuggin" + value = 42 +}