diff --git a/.gitignore b/.gitignore index 678eec6..1324c03 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -.ansible +.ansible/ testing/ vault.yml \ No newline at end of file diff --git a/group_vars/all/apps.yml b/group_vars/all/apps.yml index d125835..29b6b8d 100644 --- a/group_vars/all/apps.yml +++ b/group_vars/all/apps.yml @@ -1,7 +1,157 @@ --- -dnf_remove_repos: - - google-chrome +apps: + aichat: + cargo: [aichat] + directories: + - dest: "{{ ansible_facts['env']['HOME'] }}/.config/aichat" + mode: '0755' + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + configs: + - dest: "{{ ansible_facts['env']['HOME'] }}/.config/aichat/config.yaml" + mode: '0600' + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + content: | + # 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 }} + btrfsmaintenance: + packages: [btrfsmaintenance] + services_system_enabled: [btrfs-balance.timer, btrfs-scrub.timer, btrfs-trim.timer] + directories: + - dest: /etc/sysconfig + mode: '0755' + owner: root + group: root + configs: + - dest: /etc/sysconfig/btrfsmaintenance + mode: '0644' + owner: root + group: root + content: | + BTRFS_LOG_OUTPUT="journal" + BTRFS_DEFRAG_PATHS="" + BTRFS_DEFRAG_PERIOD="none" + BTRFS_DEFRAG_MIN_SIZE="+1M" + BTRFS_BALANCE_MOUNTPOINTS="auto" + BTRFS_BALANCE_PERIOD="weekly" + BTRFS_BALANCE_DUSAGE="0 20 50 80" + BTRFS_BALANCE_MUSAGE="80" + BTRFS_SCRUB_MOUNTPOINTS="auto" + BTRFS_SCRUB_PERIOD="quarterly" + BTRFS_SCRUB_PRIORITY="idle" + BTRFS_SCRUB_READ_ONLY="false" + BTRFS_TRIM_PERIOD="weekly" + BTRFS_TRIM_MOUNTPOINTS="auto" + BTRFS_ALLOW_CONCURRENCY="false" + + code: + packages: [code] + dnf_repos_add: + - name: code + description: Visual Studio Code + baseurl: https://packages.microsoft.com/yumrepos/vscode + gpgkey: https://packages.microsoft.com/keys/microsoft.asc + + dnf: + packages: [dnf] + configs: + - dest: /etc/dnf/dnf.conf + mode: '0644' + owner: root + group: root + content: | + [main] + # installonly_limit=3 + # best=False + skip_if_unavailable=True + deltarpm=True + fastestmirror=True + + dnf-automatic: + packages: [dnf-automatic] + services_system_enabled: [dnf-automatic.timer] + + installJRMC: + git: + - repo: https://git.bryanroessler.com/bryan/installJRMC.git + dest: "{{ ansible_facts['env']['HOME'] }}/.local/bin/installJRMC" + version: dev + + mediacenter35: + packages: [mediacenter35] + dnf_repos_add: + - name: mediacenter35 + description: JRiver Media Center hosted by BryanC + baseurl: https://repos.bryanroessler.com/jriver + gpgcheck: false + + mullvad-vpn: + packages: [mullvad-vpn] + dnf_repofiles_add: [https://repository.mullvad.net/rpm/stable/mullvad.repo] + + openwrtbuilder: + git: + - repo: https://git.bryanroessler.com/bryan/openwrtbuilder.git + dest: "{{ ansible_facts['env']['HOME'] }}/.local/bin/openwrtbuilder" + version: dev + + profile-sync-daemon: + packages: [profile-sync-daemon] + services_system_enabled: [psd.service] + + rpmfusion-free-release: + packages: [rpmfusion-free-release] + dnf_install_remote: ["https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-{{ ansible_facts['distribution_major_version'] }}.noarch.rpm"] + + openssh-server: + packages: [openssh-server] + services_system_enabled: [sshd.service] + + syncthing: + packages: [syncthing] + services_user_enabled: [syncthing.service] + + tailscale: + packages: [tailscale] + dnf_repofiles_add: [https://pkgs.tailscale.com/stable/fedora/tailscale.repo] + services_system_enabled: [tailscaled.service] + + zsh-completions: + packages: [zsh-completions] + dnf_repos_add: + - 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 + +dnf_install: + - btrfs-assistant + - calibre + - cargo + - createrepo_c + - firefox + - flatpak + - gettext + - htop + - iperf3 + - nautilus-python + - pinta + - python3-psutil + - python3-virtualenv + - python3-virtualenvwrapper + - remmina + - setroubleshoot + - ShellCheck + - snapd + - toolbox + - vim + - wl-clipboard + - zsh dnf_remove: - abrt @@ -12,55 +162,9 @@ dnf_remove: - orca - rhythmbox +dnf_repos_remove: + - google-chrome + services_system_disabled: - - qemu-guest-agent - raid-check.timer - fstrim.timer - -apps: - - btrbk - - btrfs-assistant - - btrfsmaintenance - - calibre - - cargo - - code - - dnf-automatic - - firefox - - flatpak - - gettext - - gnome-tweaks - - htop - - mediacenter35 - - mullvad-vpn - - nautilus-python - - pinta - - python3-virtualenv - - python3-virtualenvwrapper - - remmina - - https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-{{ ansible_facts['distribution_major_version'] }}.noarch.rpm - - setroubleshoot - - ShellCheck - - snapd - - syncthing - - tailscale - - toolbox - - vim - - wl-clipboard - - zsh - - zsh-completions - -git_add_repos: - - repo: https://git.bryanroessler.com/bryan/installJRMC.git - dest: "{{ ansible_facts['env']['HOME'] }}/.local/bin/installJRMC" - version: dev - - repo: https://git.bryanroessler.com/bryan/openwrtbuilder.git - dest: "{{ ansible_facts['env']['HOME'] }}/.local/bin/openwrtbuilder" - version: dev - # - repo: https://git.bryanroessler.com/bryan/deployer.git - # dest: "{{ ansible_facts['env']['HOME'] }}/.local/bin/deployer" - # version: dev - # - repo: https://git.bryanroessler.com/bryan/deploy.git - # dest: "{{ ansible_facts['env']['HOME'] }}/.local/bin/deploy" - # version: dev - - diff --git a/group_vars/all/filesystems.yml b/group_vars/all/filesystems.yml deleted file mode 100644 index 7de8b95..0000000 --- a/group_vars/all/filesystems.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- -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/sysconfig.yml b/group_vars/all/sysconfig.yml deleted file mode 100644 index 65828b5..0000000 --- a/group_vars/all/sysconfig.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -# GNOME settings via gsettings -sysconfig_gsettings: - - schema: org.gnome.nautilus.preferences - key: always-use-location-entry - value: "true" - -# Sysctl configurations -sysconfig_sysctl: - - name: fs.inotify.max_user_watches - value: 524288 - file: /etc/sysctl.d/local.conf - -# Sudoers configuration - commands that can run without password -sysconfig_sudoers_nopasswd_commands: - - /usr/bin/psd-overlay-helper - - /usr/sbin/btrfs - - /usr/bin/journalctl - - /usr/bin/dnf - - /usr/bin/fwupdmgr - - /usr/bin/dmesg diff --git a/group_vars/laptop/apps.yml b/group_vars/laptop/apps.yml index 55a2e29..ddf7bdd 100644 --- a/group_vars/laptop/apps.yml +++ b/group_vars/laptop/apps.yml @@ -1,2 +1,51 @@ apps_group: - - profile-sync-daemon \ No newline at end of file + keyd: + copr: [alternateved/keyd] + packages: [keyd] + services_system_enabled: [keyd.service] + configs: + - dest: /etc/keyd/default.conf + mode: '0644' + owner: root + group: root + content: | + [ids] + 0001:0001:09b4e68d + + [main] + leftmeta+leftshift+f23 = rightcontrol + + btrbk: + packages: [btrbk] + services_system_enabled: [btrbk.timer] + configs: + - dest: /etc/btrbk/btrbk.conf + mode: '0644' + owner: root + group: root + content: | + transaction_log /var/log/btrbk.log + ssh_identity /root/.ssh/id_ed25519 + ssh_user root + backend_local_user btrfs-progs-sudo + stream_buffer 256m + snapshot_dir .snapshots + snapshot_create onchange + lockfile /var/lock/btrbk.lock + 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 + + diff --git a/group_vars/laptop/btrbk.yml b/group_vars/laptop/btrbk.yml deleted file mode 100644 index dac9026..0000000 --- a/group_vars/laptop/btrbk.yml +++ /dev/null @@ -1,18 +0,0 @@ -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/filesystems.yml b/group_vars/laptop/filesystems.yml index 3f18c80..92a7217 100644 --- a/group_vars/laptop/filesystems.yml +++ b/group_vars/laptop/filesystems.yml @@ -1,5 +1,5 @@ --- -mounts: +filesystems_mounts: - path: /home src: /dev/disk/by-uuid/42f5911d-d634-4f92-9561-c7e20ca66c83 fstype: btrfs @@ -9,3 +9,27 @@ mounts: group: root mode: '0755' create_dir: false + +filesystem_directories: + - path: "{{ ansible_facts['env']['HOME'] }}/.local/bin" + mode: '0755' + +filesystem_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/workstation/apps.yml b/group_vars/workstation/apps.yml index e260be6..7a4a1ff 100644 --- a/group_vars/workstation/apps.yml +++ b/group_vars/workstation/apps.yml @@ -1,3 +1,88 @@ +--- +# Workstation-specific apps metadata apps_group: - - - # - profile-sync-daemon \ No newline at end of file + pwrstatd: + packages_remote: ["https://dl4jz3rbrsfum.cloudfront.net/software/PPL_64bit_v1.4.1.rpm"] + packages: [powerpanel] + services_system_enabled: [pwrstatd.service] + directories: + - dest: /etc/init.d + owner: root + group: root + configs: + - dest: /etc/pwrstatd.conf + mode: '0644' + owner: root + group: root + content: | + powerfail-delay = 60 + powerfail-active = no + powerfail-cmd-path = /etc/pwrstatd-powerfail.sh + powerfail-duration = 0 + powerfail-shutdown = no + lowbatt-threshold = 10 + runtime-threshold = 180 + lowbatt-active = no + lowbatt-cmd-path = /etc/pwrstatd-lowbatt.sh + lowbatt-duration = 0 + lowbatt-shutdown = yes + enable-alarm = yes + shutdown-sustain = 0 + turn-ups-off = no + ups-polling-rate = 5 + ups-retry-rate = 10 + prohibit-client-access = no + allowed-device-nodes = + hibernate = no + cloud-active = no + cloud-account = + + btrbk: + packages: [btrbk] + services_system_enabled: [btrbk.timer] + configs: + - dest: /etc/btrbk/btrbk.conf + mode: '0644' + owner: root + group: root + content: | + transaction_log /var/log/btrbk.log + ssh_identity /home/bryan/.config/btrbk/id_ed25519 + ssh_user root + backend_local_user btrfs-progs-sudo + stream_buffer 256m + snapshot_dir .snapshots + snapshot_create onchange + lockfile /var/lock/btrbk.lock + 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 music + + diff --git a/group_vars/workstation/btrbk.yml b/group_vars/workstation/btrbk.yml deleted file mode 100644 index 2d1f3aa..0000000 --- a/group_vars/workstation/btrbk.yml +++ /dev/null @@ -1,34 +0,0 @@ -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/filesystems.yml b/group_vars/workstation/filesystems.yml index 27657d9..123334f 100644 --- a/group_vars/workstation/filesystems.yml +++ b/group_vars/workstation/filesystems.yml @@ -1,9 +1,9 @@ --- -mounts: +filesystem_mounts: - path: /home src: /dev/disk/by-uuid/42f5911d-d634-4f92-9561-c7e20ca66c83 fstype: btrfs - opts: subvol=home,compress=zstd:1,defaults + opts: "subvol=home,compress=zstd:1,defaults" state: mounted owner: root group: root @@ -13,17 +13,17 @@ mounts: - path: /mnt/array src: /dev/disk/by-uuid/36fe5749-800a-4ab5-a89a-6ad343f5d42f fstype: btrfs - opts: defaults,compress=zstd:1,x-systemd.device-timeout=180s + opts: "defaults,compress=zstd:1,x-systemd.device-timeout=180s" state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false - path: /mnt/backup src: /dev/disk/by-uuid/64cc836d-e55f-4c34-83db-01c9b43c218a fstype: btrfs - opts: defaults,compress=zstd:1,x-systemd.device-timeout=180s,nofail + opts: "defaults,compress=zstd:1,x-systemd.device-timeout=180s,nofail" state: mounted owner: root group: root @@ -33,70 +33,70 @@ mounts: - path: /mnt/downloads src: /dev/disk/by-uuid/56a4fe2f-ce26-48cc-b602-548db7357549 fstype: btrfs - opts: defaults,compress=zstd:1 + opts: "defaults,compress=zstd:1" state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false - - path: /home/bryan/downloads + - path: /home/"{{ ansible_user }}"/downloads src: /dev/disk/by-uuid/56a4fe2f-ce26-48cc-b602-548db7357549 fstype: btrfs - opts: subvol=downloads,defaults,compress=zstd:1,x-systemd.requires=home.mount,x-gvfs-hide + opts: "subvol=downloads,defaults,compress=zstd:1,x-systemd.requires=home.mount,x-gvfs-hide" state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false - - path: /home/bryan/media + - path: "/home/{{ ansible_user }}/media" src: /dev/disk/by-uuid/36fe5749-800a-4ab5-a89a-6ad343f5d42f fstype: btrfs - opts: subvol=media,defaults,compress=zstd:1,x-systemd.requires=home.mount,x-systemd.device-timeout=180s,x-gvfs-hide + opts: "subvol=media,defaults,compress=zstd:1,x-systemd.requires=home.mount,x-systemd.device-timeout=180s,x-gvfs-hide" state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false - path: /mnt/array/media/cover-art src: /dev/disk/by-uuid/42f5911d-d634-4f92-9561-c7e20ca66c83 fstype: btrfs - opts: subvol=root/mnt/cover-art,defaults,compress=zstd:1,x-systemd.requires=mnt-array.mount,x-gvfs-hide + opts: "subvol=root/mnt/cover-art,defaults,compress=zstd:1,x-systemd.requires=mnt-array.mount,x-gvfs-hide" state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false - - path: /home/bryan/media/cover-art + - path: "/home/{{ ansible_user }}/media/cover-art" src: /dev/disk/by-uuid/42f5911d-d634-4f92-9561-c7e20ca66c83 fstype: btrfs - opts: subvol=root/mnt/cover-art,defaults,compress=zstd:1,x-systemd.requires=home-bryan-media.mount,x-gvfs-hide + opts: "subvol=root/mnt/cover-art,defaults,compress=zstd:1,x-systemd.requires=home-{{ ansible_user }}-media.mount,x-gvfs-hide" state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false - path: /mnt/array/media/ebooks src: /dev/disk/by-uuid/42f5911d-d634-4f92-9561-c7e20ca66c83 fstype: btrfs - opts: subvol=root/mnt/ebooks,defaults,compress=zstd:1,x-systemd.requires=mnt-array.mount,x-gvfs-hide + opts: "subvol=root/mnt/ebooks,defaults,compress=zstd:1,x-systemd.requires=mnt-array.mount,x-gvfs-hide" state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false - - path: /home/bryan/media/ebooks + - path: "/home/{{ ansible_user }}/media/ebooks" src: /dev/disk/by-uuid/42f5911d-d634-4f92-9561-c7e20ca66c83 fstype: btrfs - opts: subvol=root/mnt/ebooks,defaults,compress=zstd:1,x-systemd.requires=home-bryan-media.mount,x-gvfs-hide + opts: "subvol=root/mnt/ebooks,defaults,compress=zstd:1,x-systemd.requires=home-{{ ansible_user }}-media.mount,x-gvfs-hide" state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false @@ -105,27 +105,53 @@ mounts: fstype: btrfs opts: subvol=root/mnt/screenshots,defaults,compress=zstd:1,x-systemd.requires=mnt-array.mount,x-gvfs-hide state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false - - path: /home/bryan/media/pictures/Screenshots + - path: "/home/{{ ansible_user }}/media/pictures/Screenshots" src: /dev/disk/by-uuid/42f5911d-d634-4f92-9561-c7e20ca66c83 fstype: btrfs - opts: subvol=root/mnt/screenshots,defaults,compress=zstd:1,x-systemd.requires=home-bryan-media.mount,x-gvfs-hide + opts: "subvol=root/mnt/screenshots,defaults,compress=zstd:1,x-systemd.requires=home-{{ ansible_user }}-media.mount,x-gvfs-hide" state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false - - path: /home/bryan/devices/laptop/music + - path: "/home/{{ ansible_user }}/devices/laptop/music" src: /dev/disk/by-uuid/d0ed963e-aaa0-4dcc-9ece-4ea8fe7fcea2 fstype: btrfs opts: defaults,compress=zstd:1,x-systemd.requires=home.mount,x-gvfs-hide state: mounted - owner: bryan - group: bryan + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" mode: '0755' create_dir: false + +filesystem_directories: + - path: "/home/{{ ansible_user }}/.local/bin" + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: '0755' + +filesystem_symlinks: + - name: develop + src: "/home/{{ ansible_user }}/documents/develop" + dest: "/home/{{ ansible_user }}/develop" + - name: music + src: "/home/{{ ansible_user }}/media/music" + dest: "/home/{{ ansible_user }}/music" + - name: pictures + src: "/home/{{ ansible_user }}/media/pictures" + dest: "/home/{{ ansible_user }}/pictures" + - name: videos + src: "/home/{{ ansible_user }}/media/videos" + dest: "/home/{{ ansible_user }}/videos" + - name: ebooks + src: "/home/{{ ansible_user }}/media/ebooks" + dest: "/home/{{ ansible_user }}/ebooks" + - name: bin + src: "/home/{{ ansible_user }}/.local/bin" + dest: "/home/{{ ansible_user }}/bin" \ No newline at end of file diff --git a/group_vars/workstation/quadlets.yml b/group_vars/workstation/quadlets.yml index ca4f35f..3c64016 100644 --- a/group_vars/workstation/quadlets.yml +++ b/group_vars/workstation/quadlets.yml @@ -1,5 +1,4 @@ --- - quadlets_deploy_configs: true # deploy quadlet service configs maintainer: "Bryan C. Roessler" diff --git a/playbook.yml b/playbook.yml index 026acfb..b30f262 100644 --- a/playbook.yml +++ b/playbook.yml @@ -5,12 +5,6 @@ - role: filesystems tags: ['filesystems'] -- name: Deploy users - hosts: all - roles: - - role: users - tags: ['users'] - - name: Deploy scripts hosts: all roles: @@ -23,18 +17,24 @@ - role: dotfiles tags: ['dotfiles'] +- name: Deploy apps + hosts: all + roles: + - role: apps + tags: ['apps'] + +- name: Deploy users + hosts: all + roles: + - role: users + tags: ['users'] + - name: Deploy sysconfig hosts: all roles: - role: sysconfig tags: ['sysconfig'] -- name: Deploy apps - hosts: all - roles: - - role: apps - tags: ['apps'] - - name: Deploy quadlets hosts: all roles: diff --git a/roles/apps/README.md b/roles/apps/README.md new file mode 100644 index 0000000..473a0f4 diff --git a/roles/apps/aichat.yml b/roles/apps/aichat.yml deleted file mode 100644 index d5c9807..0000000 --- a/roles/apps/aichat.yml +++ /dev/null @@ -1,13 +0,0 @@ -cargo: - - 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 deleted file mode 100644 index c418ba2..0000000 --- a/roles/apps/btrbk.yml +++ /dev/null @@ -1,124 +0,0 @@ -system_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 deleted file mode 100644 index e56c196..0000000 --- a/roles/apps/btrfsmaintenance.yml +++ /dev/null @@ -1,162 +0,0 @@ -system_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 deleted file mode 100644 index 181df15..0000000 --- a/roles/apps/code.yml +++ /dev/null @@ -1,5 +0,0 @@ -repos: - - 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 deleted file mode 100644 index 3c35b6a..0000000 --- a/roles/apps/dnf-automatic.yml +++ /dev/null @@ -1,2 +0,0 @@ -system_services: - - dnf-automatic.timer \ No newline at end of file diff --git a/roles/apps/dnf.yml b/roles/apps/dnf.yml deleted file mode 100644 index fd4e623..0000000 --- a/roles/apps/dnf.yml +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 7b15837..0000000 --- a/roles/apps/keyd.yml +++ /dev/null @@ -1,14 +0,0 @@ -copr: - - alternateved/keyd - -system_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 deleted file mode 100644 index b4aa3a9..0000000 --- a/roles/apps/mediacenter35.yml +++ /dev/null @@ -1,5 +0,0 @@ -repos: - - 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 deleted file mode 100644 index 88957fe..0000000 --- a/roles/apps/mullvad-vpn.yml +++ /dev/null @@ -1,3 +0,0 @@ -repofiles: - - 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 deleted file mode 100644 index daae9e8..0000000 --- a/roles/apps/profile-sync-daemon.yml +++ /dev/null @@ -1,2 +0,0 @@ -user_services: - - psd.service \ No newline at end of file diff --git a/roles/apps/pwrstatd.yml b/roles/apps/pwrstatd.yml deleted file mode 100644 index f30bc4b..0000000 --- a/roles/apps/pwrstatd.yml +++ /dev/null @@ -1,140 +0,0 @@ -packages: - - "https://dl4jz3rbrsfum.cloudfront.net/software/PPL_64bit_v1.4.1.rpm" - -system_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 deleted file mode 100644 index 749ec7d..0000000 --- a/roles/apps/tailscale.yml +++ /dev/null @@ -1,2 +0,0 @@ -system_services: - - tailscaled.service \ No newline at end of file diff --git a/roles/apps/tasks/cargo.yml b/roles/apps/tasks/cargo.yml new file mode 100644 index 0000000..a5818b3 --- /dev/null +++ b/roles/apps/tasks/cargo.yml @@ -0,0 +1,5 @@ +- name: Install cargo packages + community.general.cargo: + name: "{{ item }}" + state: present + loop: "{{ apps_cargo | default([]) + (cargo_install | default([])) }}" diff --git a/roles/apps/tasks/configs.yml b/roles/apps/tasks/configs.yml new file mode 100644 index 0000000..e1e7fa7 --- /dev/null +++ b/roles/apps/tasks/configs.yml @@ -0,0 +1,31 @@ +- name: Create app directories + ansible.builtin.file: + path: "{{ item.dest }}" + state: directory + mode: "0755" + owner: "{{ item.owner | default(omit) }}" + group: "{{ item.group | default(omit) }}" + loop: "{{ apps_directories }}" + become: "{{ item.owner is defined and item.owner == 'root' }}" + when: apps_directories is defined and apps_directories | length > 0 + +- name: Create parent directories for config files + ansible.builtin.file: + path: "{{ item.dest | dirname }}" + state: directory + mode: '0755' + loop: "{{ apps_configs }}" + become: "{{ item.owner is defined and item.owner == 'root' }}" + when: apps_configs is defined and apps_configs | length > 0 + +- name: Deploy configuration templates + ansible.builtin.copy: + content: "{{ item.content }}" + dest: "{{ item.dest }}" + mode: "{{ item.mode | default('0644') }}" + owner: "{{ item.owner | default(omit) }}" + group: "{{ item.group | default(omit) }}" + backup: "{{ item.backup | default(false) }}" + loop: "{{ apps_configs }}" + become: "{{ item.owner is defined and item.owner == 'root' }}" + when: apps_configs is defined and apps_configs | length > 0 \ No newline at end of file diff --git a/roles/apps/tasks/dnf.yml b/roles/apps/tasks/dnf.yml new file mode 100644 index 0000000..d62199e --- /dev/null +++ b/roles/apps/tasks/dnf.yml @@ -0,0 +1,69 @@ +--- +- name: Enable COPR repositories + community.general.copr: + name: "{{ item.repo | default(item) }}" + state: enabled + loop: "{{ (copr_install | default([])) + (apps_copr | default([])) }}" + become: true + +- name: Add DNF repositories + ansible.builtin.yum_repository: + name: "{{ item.name }}" + description: "{{ item.description | default(omit) }}" + baseurl: "{{ item.baseurl | default(omit) }}" + metalink: "{{ item.metalink | default(omit) }}" + enabled: "{{ item.enabled | default(true) }}" + metadata_expire: "{{ item.metadata_expire | default(omit) }}" + gpgcheck: "{{ item.gpgcheck | default(true) }}" + repo_gpgcheck: "{{ item.repo_gpgcheck | default(omit) }}" + gpgkey: "{{ item.gpgkey | default(omit) }}" + loop: "{{ (dnf_repos_add | default([])) + (apps_dnf_repos_add | default([])) }}" + become: true + +- name: Add DNF repository files + ansible.builtin.get_url: + url: "{{ item.url | default(item) }}" + dest: "/etc/yum.repos.d/{{ (item.url | default(item)) | basename }}" + owner: root + group: root + mode: '0644' + loop: "{{ (dnf_repofiles_add | default([])) + (apps_dnf_repofiles_add | default([])) }}" + become: true + +- name: Remove DNF repositories + ansible.builtin.yum_repository: + name: "{{ item }}" + state: absent + loop: "{{ dnf_repos_remove | default([]) }}" + become: true + +- name: Install remote RPM packages (from URLs) + ansible.builtin.dnf: + name: "{{ (dnf_install_remote | default([])) + (apps_dnf_install_remote | default([])) + (apps_packages_remote | default([])) }}" + state: present + disable_gpg_check: true + become: true + when: ((dnf_install_remote | default([])) + (apps_dnf_install_remote | default([])) + (apps_packages_remote | default([]))) | length > 0 + +- name: Remove unwanted packages + ansible.builtin.dnf: + name: "{{ item }}" + state: absent + autoremove: true + loop: "{{ dnf_remove | default([]) }}" + failed_when: false + become: true + +- name: Install packages + ansible.builtin.dnf: + name: "{{ apps_all_packages }}" + state: present + skip_broken: true + become: true + +- name: Update all packages + ansible.builtin.dnf: + name: "*" + state: latest # noqa package-latest + skip_broken: true + become: true \ No newline at end of file diff --git a/roles/apps/tasks/git.yml b/roles/apps/tasks/git.yml new file mode 100644 index 0000000..eec4194 --- /dev/null +++ b/roles/apps/tasks/git.yml @@ -0,0 +1,10 @@ +- name: Clone git repositories + ansible.builtin.git: + repo: "{{ item.repo }}" + dest: "{{ item.dest }}" + version: "{{ item.version }}" + update: true + depth: 1 + accept_hostkey: true + loop: "{{ (git | default([])) + (apps_git | default([])) }}" + when: ((git | default([])) + (apps_git | default([]))) | length > 0 \ No newline at end of file diff --git a/roles/apps/tasks/main.yml b/roles/apps/tasks/main.yml index bd9a863..2ac4cc4 100644 --- a/roles/apps/tasks/main.yml +++ b/roles/apps/tasks/main.yml @@ -1,137 +1,39 @@ --- -- name: Load per-app configuration files - ansible.builtin.include_vars: - file: "{{ role_path }}/{{ item }}.yml" - name: "app_{{ item }}" - loop: "{{ ((apps | default([])) + (apps_group | default([]))) | select | list }}" - failed_when: false - -- name: Merge app configuration +# Merge all apps dicts (apps + apps_group) +- name: Merge apps configurations ansible.builtin.set_fact: - apps_copr: "{{ apps_copr | default([]) + (lookup('vars', 'app_' + item, default={}).copr | default([])) }}" - apps_repos: "{{ apps_repos | default([]) + (lookup('vars', 'app_' + item, default={}).repos | default([])) }}" - apps_repofiles: "{{ apps_repofiles | default([]) + (lookup('vars', 'app_' + item, default={}).repofiles | default([])) }}" - apps_packages: "{{ apps_packages | default([]) + (lookup('vars', 'app_' + item, default={}).packages | default([])) }}" - apps_cargo: "{{ apps_cargo | default([]) + (lookup('vars', 'app_' + item, default={}).cargo | default([])) }}" - apps_system_services: "{{ apps_system_services | default([]) + (lookup('vars', 'app_' + item, default={}).system_services | default([])) }}" - apps_user_services: "{{ apps_user_services | default([]) + (lookup('vars', 'app_' + item, default={}).user_services | default([])) }}" - loop: "{{ ((apps | default([])) + (apps_group | default([]))) | select | list }}" + apps_all_apps: "{{ apps | default({}) | combine(apps_group | default({}), recursive=True) }}" -- name: Enable COPR repositories - community.general.copr: - name: "{{ item.repo | default(item) }}" - state: enabled - loop: "{{ apps_copr | default([]) }}" - become: true +# Extract various lists from merged apps +- name: Build package and config lists + ansible.builtin.set_fact: + apps_packages: "{{ apps_all_apps | dict2items | selectattr('value.packages', 'defined') | map(attribute='value.packages') | flatten }}" + apps_packages_remote: "{{ apps_all_apps | dict2items | selectattr('value.packages_remote', 'defined') | map(attribute='value.packages_remote') | flatten }}" + apps_cargo: "{{ apps_all_apps | dict2items | selectattr('value.cargo', 'defined') | map(attribute='value.cargo') | flatten }}" + apps_copr: "{{ apps_all_apps | dict2items | selectattr('value.copr', 'defined') | map(attribute='value.copr') | flatten }}" + apps_git: "{{ apps_all_apps | dict2items | selectattr('value.git', 'defined') | map(attribute='value.git') | flatten }}" + apps_configs: "{{ apps_all_apps | dict2items | selectattr('value.configs', 'defined') | map(attribute='value.configs') | flatten }}" + apps_directories: "{{ apps_all_apps | dict2items | selectattr('value.directories', 'defined') | map(attribute='value.directories') | flatten }}" + apps_dnf_repos_add: "{{ apps_all_apps | dict2items | selectattr('value.dnf_repos_add', 'defined') | map(attribute='value.dnf_repos_add') | flatten }}" + apps_dnf_repofiles_add: "{{ apps_all_apps | dict2items | selectattr('value.dnf_repofiles_add', 'defined') | map(attribute='value.dnf_repofiles_add') | flatten }}" + apps_dnf_install_remote: "{{ apps_all_apps | dict2items | selectattr('value.dnf_install_remote', 'defined') | map(attribute='value.dnf_install_remote') | flatten }}" + apps_services_system_enabled: "{{ apps_all_apps | dict2items | selectattr('value.services_system_enabled', 'defined') | map(attribute='value.services_system_enabled') | flatten }}" + apps_services_system_disabled: "{{ apps_all_apps | dict2items | selectattr('value.services_system_disabled', 'defined') | map(attribute='value.services_system_disabled') | flatten }}" + apps_services_user_enabled: "{{ apps_all_apps | dict2items | selectattr('value.services_user_enabled', 'defined') | map(attribute='value.services_user_enabled') | flatten }}" + apps_services_user_disabled: "{{ apps_all_apps | dict2items | selectattr('value.services_user_disabled', 'defined') | map(attribute='value.services_user_disabled') | flatten }}" + apps_all_packages: "{{ (apps_packages | default([])) + (dnf_install | default([])) }}" -- name: Add DNF repositories - ansible.builtin.yum_repository: - name: "{{ item.name }}" - description: "{{ item.description | default(omit) }}" - baseurl: "{{ item.baseurl | default(omit) }}" - metalink: "{{ item.metalink | default(omit) }}" - enabled: "{{ item.enabled | default(true) }}" - metadata_expire: "{{ item.metadata_expire | default(omit) }}" - gpgcheck: "{{ item.gpgcheck | default(true) }}" - repo_gpgcheck: "{{ item.repo_gpgcheck | default(omit) }}" - gpgkey: "{{ item.gpgkey | default(omit) }}" - loop: "{{ (dnf_add_repos | default([])) + (apps_repos | default([])) }}" - become: true - -- name: Add DNF repository files - ansible.builtin.get_url: - url: "{{ item.url }}" - dest: "/etc/yum.repos.d/{{ item.url | basename }}" - owner: root - group: root - mode: '0644' - loop: "{{ apps_repofiles | default([]) }}" - become: true - -- name: Remove DNF repositories - ansible.builtin.yum_repository: - name: "{{ item }}" - state: absent - loop: "{{ (dnf_remove_repos | default([])) + (dnf_remove_repos_group | default([])) }}" - become: true - -- name: Remove unwanted packages - ansible.builtin.dnf: - name: "{{ item }}" - state: absent - autoremove: true - loop: "{{ (dnf_remove | default([])) + (dnf_remove_group | default([])) }}" - become: true - failed_when: false - -- name: Install remote RPM packages (from URLs) - ansible.builtin.dnf: - name: "{{ apps_packages | default([]) | select('match', '^https?://') | list }}" - state: present - disable_gpg_check: true - become: true - when: (apps_packages | default([]) | select('match', '^https?://') | list) | length > 0 - -- name: Install DNF packages - ansible.builtin.dnf: - name: "{{ ((apps | default([])) + (apps_group | default([])) + (apps_packages | default([]) | reject('match', '^https?://') | list)) | select | list }}" - state: present - skip_broken: true - become: true - -- name: Update all DNF packages - ansible.builtin.dnf: - name: "*" - state: latest # noqa package-latest - skip_broken: true - become: true - -- name: Install cargo packages - ansible.builtin.command: - cmd: "cargo install {{ item }}" - loop: "{{ apps_cargo | default([]) }}" - 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: Deploy repositorioes and packages + ansible.builtin.include_tasks: dnf.yml - name: Clone git repositories - ansible.builtin.git: - repo: "{{ item.repo }}" - dest: "{{ item.dest }}" - version: "{{ item.version }}" - update: true - loop: "{{ (git_add_repos | default([])) + (git_add_repos_group | default([])) }}" + ansible.builtin.include_tasks: git.yml -- 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([])) + (apps_system_services | default([])) }}" - become: true +- name: Install cargo packages + ansible.builtin.include_tasks: cargo.yml -- 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: Deploy app configs + ansible.builtin.include_tasks: configs.yml -- 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([])) + (apps_user_services | default([])) }}" - -- name: Disable and stop user services - ansible.builtin.systemd: - name: "{{ item }}" - enabled: false - state: stopped - scope: user - loop: "{{ (services_user_disabled | default([])) + (services_user_disabled_group | default([])) }}" \ No newline at end of file +- name: Enable and start/stop system and user services + ansible.builtin.include_tasks: services.yml diff --git a/roles/apps/tasks/services.yml b/roles/apps/tasks/services.yml new file mode 100644 index 0000000..d053c8f --- /dev/null +++ b/roles/apps/tasks/services.yml @@ -0,0 +1,37 @@ +- name: Enable and start system services + ansible.builtin.systemd: + name: "{{ item }}" + enabled: true + state: started + scope: system + loop: "{{ ((services_system_enabled | default([])) + (apps_services_system_enabled | default([]))) | unique }}" + become: true + failed_when: false + +- name: Disable and stop system services + ansible.builtin.systemd: + name: "{{ item }}" + enabled: false + state: stopped + scope: system + loop: "{{ ((services_system_disabled | default([])) + (apps_services_system_disabled | default([]))) | unique }}" + become: true + failed_when: false + +- name: Enable and start user services + ansible.builtin.systemd: + name: "{{ item }}" + enabled: true + state: started + scope: user + loop: "{{ ((services_user_enabled | default([])) + (apps_services_user_enabled | default([]))) | unique }}" + failed_when: false + +- name: Disable and stop user services + ansible.builtin.systemd: + name: "{{ item }}" + enabled: false + state: stopped + scope: user + loop: "{{ ((services_user_disabled | default([])) + (apps_services_user_disabled | default([]))) | unique }}" + failed_when: false diff --git a/roles/apps/zsh-completions.yml b/roles/apps/zsh-completions.yml deleted file mode 100644 index 49b91f2..0000000 --- a/roles/apps/zsh-completions.yml +++ /dev/null @@ -1,5 +0,0 @@ -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 \ No newline at end of file diff --git a/roles/deploy_files.yml b/roles/deploy_files.yml deleted file mode 100644 index 567c668..0000000 --- a/roles/deploy_files.yml +++ /dev/null @@ -1,54 +0,0 @@ ---- -# Reusable task to deploy files and templates from role paths -# Parameters: -# - subdir: subdirectory under role// (e.g., 'home', 'root') (optional, default: '') -# - target_root: target root path (e.g., ansible_facts.env.HOME, '/etc') -# - use_symlinks: bool, whether to use symlinks for local deployments (default: true) -# - become_root: bool, whether to become root (default: false) - -- name: "Build file lists for {{ var_prefix }}" - ansible.builtin.set_fact: - "{{ var_prefix }}_files": "{{ lookup('community.general.filetree', - role_path ~ '/' ~ (subdir | default('')), wantlist=True) | selectattr('state', 'equalto', 'file') | rejectattr('path', 'match', '.*\\.j2$') | list }}" - "{{ var_prefix }}_templates": "{{ lookup('community.general.filetree', - role_path ~ '/' ~ (subdir | default('')), wantlist=True) | selectattr('state', 'equalto', 'file') | selectattr('path', 'match', '.*\\.j2$') | list }}" - -- name: "Ensure directories exist for {{ var_prefix }}" - ansible.builtin.file: - path: "{{ target_root }}/{{ item.path | dirname }}" - state: directory - mode: "0755" - loop: "{{ lookup('vars', var_prefix ~ '_files') + lookup('vars', var_prefix ~ '_templates') }}" - when: item.path | dirname != '' - become: "{{ become_root | default(false) }}" - -- name: "Deploy files (local with symlinks) for {{ var_prefix }}" - ansible.builtin.file: - src: "{{ item.src }}" - dest: "{{ target_root }}/{{ item.path }}" - state: link - force: true - loop: "{{ lookup('vars', var_prefix ~ '_files') }}" - when: - - ansible_connection in ['local', 'localhost'] - - use_symlinks | default(true) - become: "{{ become_root | default(false) }}" - -- name: "Deploy files (local/remote copy) for {{ var_prefix }}" - ansible.builtin.copy: - src: "{{ item.src }}" - dest: "{{ target_root }}/{{ item.path }}" - mode: preserve - loop: "{{ lookup('vars', var_prefix ~ '_files') }}" - when: | - (ansible_connection not in ['local', 'localhost']) or - (not (use_symlinks | default(true))) - become: "{{ become_root | default(false) }}" - -- name: "Render templates for {{ var_prefix }}" - ansible.builtin.template: - src: "{{ item.src }}" - dest: "{{ target_root }}/{{ item.path | replace('.j2', '') }}" - mode: preserve - loop: "{{ lookup('vars', var_prefix ~ '_templates') }}" - become: "{{ become_root | default(false) }}" diff --git a/roles/dotfiles/ssh/.ssh/config b/roles/dotfiles/ssh/.ssh/config index 36282ec..9d00413 100644 --- a/roles/dotfiles/ssh/.ssh/config +++ b/roles/dotfiles/ssh/.ssh/config @@ -36,7 +36,7 @@ Host laptop Hostname laptop Host vm-fedora43 - Hostname 192.168.122.169 + Hostname 192.168.122.241 Host vm-alma9 Hostname 192.168.122.235 diff --git a/roles/dotfiles/tasks/main.yml b/roles/dotfiles/tasks/main.yml index 435236f..a66115e 100644 --- a/roles/dotfiles/tasks/main.yml +++ b/roles/dotfiles/tasks/main.yml @@ -6,11 +6,13 @@ depth: 1 excludes: ['tasks', 'templates', 'files', 'vars', 'defaults', 'meta', 'handlers'] register: dotfiles_packages + delegate_to: localhost - 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 }}" + delegate_to: localhost - name: Ensure dotfile directories exist ansible.builtin.file: @@ -18,7 +20,6 @@ state: directory mode: "0755" loop: "{{ dotfiles_files }}" - when: item.path | dirname != '' - name: Deploy dotfiles (local with symlinks) ansible.builtin.file: @@ -27,7 +28,7 @@ state: link force: true loop: "{{ dotfiles_files | rejectattr('path', 'match', '.*\\.j2$') | list }}" - when: ansible_connection in ['local', 'localhost'] + when: ansible_connection == 'local' - name: Deploy dotfiles (remote with copy) ansible.builtin.copy: @@ -35,11 +36,11 @@ dest: "{{ ansible_facts.env.HOME }}/{{ item.path }}" mode: preserve loop: "{{ dotfiles_files | rejectattr('path', 'match', '.*\\.j2$') | list }}" - when: ansible_connection not in ['local', 'localhost'] + when: ansible_connection != 'local' - 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 + loop: "{{ dotfiles_files | selectattr('path', 'match', '.*\\.j2$') | list }}" diff --git a/roles/filesystems/tasks/main.yml b/roles/filesystems/tasks/main.yml index cb0a1f3..bf8917b 100644 --- a/roles/filesystems/tasks/main.yml +++ b/roles/filesystems/tasks/main.yml @@ -6,7 +6,7 @@ owner: "{{ item.owner | default('root') }}" group: "{{ item.group | default('root') }}" mode: "{{ item.mode | default('0755') }}" - loop: "{{ mounts | default([]) }}" + loop: "{{ filesystem_mounts | default([]) }}" become: true when: item.create_dir | default(false) | bool @@ -15,7 +15,7 @@ path: "{{ item.path }}" register: filesystems_mounts_stat changed_when: false - loop: "{{ mounts | default([]) }}" + loop: "{{ filesystem_mounts | default([]) }}" - name: Assert mount points exist ansible.builtin.assert: @@ -32,7 +32,7 @@ opts: "{{ item.opts | default('defaults') }}" state: "{{ item.state | default('mounted') }}" backup: true - loop: "{{ mounts | default([]) }}" + loop: "{{ filesystem_mounts | default([]) }}" become: true - name: Ensure directories exist @@ -40,7 +40,10 @@ path: "{{ item.path }}" state: directory mode: "{{ item.mode | default('0755') }}" - loop: "{{ directories | default([]) }}" + owner: "{{ item.owner | default(omit) }}" + group: "{{ item.group | default(omit) }}" + loop: "{{ filesystem_directories | default([]) }}" + become: "{{ (item.owner is defined and item.owner == 'root') }}" - name: Deploy symlinks ansible.builtin.file: @@ -48,4 +51,4 @@ dest: "{{ item.dest }}" state: link force: true - loop: "{{ symlinks | default([]) }}" + loop: "{{ filesystem_symlinks | default([]) }}" diff --git a/roles/quadlets/prowlarr.yml b/roles/quadlets/prowlarr.yml index 9c0d6d2..77f3093 100644 --- a/roles/quadlets/prowlarr.yml +++ b/roles/quadlets/prowlarr.yml @@ -37,7 +37,7 @@ quadlets: 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__SSLPORT: "{{ PROWLARR__SERVER__SSLPORT | 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) }}" diff --git a/roles/quadlets/tasks/main.yml b/roles/quadlets/tasks/main.yml index 0a20eb7..442c17f 100644 --- a/roles/quadlets/tasks/main.yml +++ b/roles/quadlets/tasks/main.yml @@ -2,18 +2,14 @@ - 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 }}" + loop: "{{ lookup('ansible.builtin.find', role_path, patterns='*.yml', excludes=['tasks']).files }}" -- name: Deploy app configs from metadata +- name: Deploy app configs ansible.builtin.template: content: "{{ item.1.template }}" - dest: "{{ target_root }}/{{ item.1.path }}" + dest: "{{ item.1.path }}" mode: '0644' loop: "{{ quadlets_apps | subelements('configs', skip_missing=True) }}" - vars: - 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 diff --git a/roles/scripts/tasks/main.yml b/roles/scripts/tasks/main.yml index 8517710..dd94ece 100644 --- a/roles/scripts/tasks/main.yml +++ b/roles/scripts/tasks/main.yml @@ -19,7 +19,7 @@ state: link force: true loop: "{{ scripts_files.files }}" - when: ansible_connection in ['local', 'localhost'] + when: ansible_connection == 'local' - name: "Deploy scripts (remote with copy)" ansible.builtin.copy: @@ -27,4 +27,4 @@ dest: "{{ ansible_facts.env.HOME }}/.local/bin/{{ item.path | basename }}" mode: '0755' loop: "{{ scripts_files.files }}" - when: ansible_connection not in ['local', 'localhost'] + when: ansible_connection != 'local' diff --git a/roles/sysconfig/tasks/main.yml b/roles/sysconfig/tasks/main.yml index 4d431da..54e0656 100644 --- a/roles/sysconfig/tasks/main.yml +++ b/roles/sysconfig/tasks/main.yml @@ -1,5 +1,4 @@ --- - - name: Configure sysctl parameters ansible.posix.sysctl: name: "{{ item.name }}" @@ -7,23 +6,26 @@ sysctl_file: "{{ item.file }}" state: present reload: true - loop: "{{ sysconfig_sysctl }}" + loop: + - name: fs.inotify.max_user_watches + value: 524288 + file: /etc/sysctl.d/local.conf become: true - when: sysconfig_sysctl is defined and sysconfig_sysctl | length > 0 - name: Configure GNOME settings community.general.dconf: key: "/{{ item.schema | replace('.', '/') }}/{{ item.key }}" value: "{{ item.value }}" state: present - loop: "{{ sysconfig_gsettings }}" - when: sysconfig_gsettings is defined and sysconfig_gsettings | length > 0 + loop: + - schema: org.gnome.nautilus.preferences + key: always-use-location-entry + value: "true" - name: Configure sudoers for passwordless commands ansible.builtin.lineinfile: path: /etc/sudoers - line: "{{ ansible_facts['user_id'] }} ALL=(ALL) NOPASSWD: {{ sysconfig_sudoers_nopasswd_commands | join(', ') }}" + line: "{{ ansible_user }} ALL=(ALL) NOPASSWD: /usr/bin/psd-overlay-helper, /usr/bin/btrfs, /usr/bin/journalctl, /usr/bin/dnf, /usr/bin/fwupdmgr, /usr/bin/dmesg" state: present - validate: /usr/sbin/visudo -cf %s + validate: /usr/bin/visudo -cf %s become: true - when: sysconfig_sudoers_nopasswd_commands is defined and sysconfig_sudoers_nopasswd_commands | length > 0 diff --git a/roles/users/tasks/main.yml b/roles/users/tasks/main.yml index c1624f4..9d70fda 100644 --- a/roles/users/tasks/main.yml +++ b/roles/users/tasks/main.yml @@ -1,6 +1,13 @@ -- name: Set user shell +- name: Create user and set shell ansible.builtin.user: name: "{{ item.name }}" shell: "{{ item.shell }}" loop: "{{ users }}" become: true + +- name: Enable lingering for user services + ansible.builtin.command: + cmd: "loginctl enable-linger {{ item.name }}" + loop: "{{ users }}" + changed_when: false + become: true \ No newline at end of file