---
- name: Prepare System
  hosts: all
  become: true
  gather_facts: true
  any_errors_fatal: true
  pre_tasks:
    - name: Pausing for 2 seconds...
      ansible.builtin.pause:
        seconds: 2
  tasks:
    - name: Locale
      block:
        - name: Locale | Set timezone
          community.general.timezone:
            name: "{{ timezone | default('Etc/UTC') }}"

    - name: Packages
      block:
        - name: Packages | Add fish key
          ansible.builtin.get_url:
            url: https://download.opensuse.org/repositories/shells:fish:release:3/Debian_12/Release.key
            dest: /etc/apt/trusted.gpg.d/fish.asc
            owner: root
            group: root
            mode: "0644"
        - name: Packages | Add fish repository
          ansible.builtin.apt_repository:
            repo: deb [signed-by=/etc/apt/trusted.gpg.d/fish.asc] http://download.opensuse.org/repositories/shells:/fish:/release:/3/Debian_12/ /
            filename: fish
            update_cache: true
        - name: Packages | Add non-free repository
          ansible.builtin.apt_repository:
            repo: deb http://deb.debian.org/debian/ stable main contrib non-free
            filename: non-free
            update_cache: true
        - name: Packages | Install
          ansible.builtin.apt:
            name: apt-transport-https,ca-certificates,conntrack,curl,dirmngr,fish,gdisk,
              gnupg,hdparm,htop,iperf3,iptables,iputils-ping,ipvsadm,
              libseccomp2,lm-sensors,neofetch,net-tools,nfs-common,nvme-cli,open-iscsi,parted,psmisc,python3,
              python3-apt,python3-kubernetes,python3-yaml,smartmontools,socat,software-properties-common,
              unzip,util-linux
            install_recommends: false

    - name: User Configuration
      block:
        - name: User Configuration | SSH keys
          ansible.posix.authorized_key:
            user: "{{ ansible_user }}"
            key: "https://github.com/{{ github_username }}.keys"
        - name: User Configuration | Silence login
          ansible.builtin.file:
            dest: "{{ '/home/' + ansible_user if ansible_user != 'root' else '/root' }}/.hushlogin"
            state: touch
            owner: "{{ ansible_user }}"
            group: "{{ ansible_user }}"
            mode: "0644"
            modification_time: preserve
            access_time: preserve
        - name: User Configuration | Add user to sudoers
          when: ansible_user != 'root'
          ansible.builtin.copy:
            content: "{{ ansible_user }} ALL=(ALL:ALL) NOPASSWD:ALL"
            dest: "/etc/sudoers.d/{{ ansible_user }}"
            owner: root
            group: root
            mode: "0440"
        - name: User Configuration | Fish shell (1)
          ansible.builtin.user:
            name: "{{ ansible_user }}"
            shell: /usr/bin/fish
        - name: User Configuration | Fish shell (2)
          ansible.builtin.file:
            path: "{{ '/home/' + ansible_user if ansible_user != 'root' else '/root' }}/.config/fish/functions"
            state: directory
            owner: "{{ ansible_user }}"
            group: "{{ ansible_user }}"
            recurse: true
        - name: User Configuration | Fish shell (3)
          ansible.builtin.copy:
            dest: "{{ '/home/' + ansible_user if ansible_user != 'root' else '/root' }}/.config/fish/functions/fish_greeting.fish"
            owner: "{{ ansible_user }}"
            group: "{{ ansible_user }}"
            mode: "0755"
            content: neofetch --config none
        - name: User Configuration | Fish shell (3)
          ansible.builtin.copy:
            dest: "{{ '/home/' + ansible_user if ansible_user != 'root' else '/root' }}/.config/fish/functions/k.fish"
            owner: "{{ ansible_user }}"
            group: "{{ ansible_user }}"
            mode: "0755"
            content: |
              function k --wraps=kubectl --description 'kubectl shorthand'
                  kubectl $argv
              end

    - name: Network Configuration
      notify: Reboot
      block:
        - name: Network Configuration | Set hostname
          ansible.builtin.hostname:
            name: "{{ inventory_hostname }}"
        - name: Network Configuration | Update hosts
          ansible.builtin.copy:
            dest: /etc/hosts
            content: |
              127.0.0.1 localhost
              127.0.1.1 {{ inventory_hostname }}

              # The following lines are desirable for IPv6 capable hosts
              ::1     localhost ip6-localhost ip6-loopback
              ff02::1 ip6-allnodes
              ff02::2 ip6-allrouters
            mode: preserve
        # https://github.com/cilium/cilium/issues/18706
        - name: Network Configuration | Cilium (1)
          ansible.builtin.lineinfile:
            dest: /etc/systemd/networkd.conf
            regexp: ManageForeignRoutingPolicyRules
            line: ManageForeignRoutingPolicyRules=no
        - name: Network Configuration | Cilium (2)
          ansible.builtin.lineinfile:
            dest: /etc/systemd/networkd.conf
            regexp: ManageForeignRoutes
            line: ManageForeignRoutes=no

    - name: System Configuration
      notify: Reboot
      block:
        - name: System Configuration | Neofetch
          ansible.builtin.copy:
            dest: /etc/profile.d/neofetch.sh
            mode: "0755"
            content: neofetch --config none
        - name: System Configuration | Disable swap
          ansible.posix.mount:
            name: "{{ item }}"
            fstype: swap
            state: absent
          loop: ["none", "swap"]
        - name: System Configuration | Kernel modules (1)
          community.general.modprobe:
            name: "{{ item }}"
            state: present
          loop: ["br_netfilter", "ceph", "ip_vs", "ip_vs_rr", "nbd", "overlay", "rbd"]
        - name: System Configuration | Kernel modules (2)
          ansible.builtin.copy:
            dest: "/etc/modules-load.d/{{ item }}.conf"
            mode: "0644"
            content: "{{ item }}"
          loop: ["br_netfilter", "ceph", "ip_vs", "ip_vs_rr", "nbd", "overlay", "rbd"]
        - name: System Configuration | Sysctl
          ansible.posix.sysctl:
            name: "{{ item.key }}"
            value: "{{ item.value }}"
            sysctl_file: /etc/sysctl.d/99-kubernetes.conf
            reload: true
          with_dict: "{{ sysctl_config }}"
          vars:
            sysctl_config:
              fs.inotify.max_queued_events: 65536
              fs.inotify.max_user_watches: 524288
              fs.inotify.max_user_instances: 8192
        - name: System Configuration | Grub (1)
          ansible.builtin.replace:
            path: /etc/default/grub
            regexp: '^(GRUB_CMDLINE_LINUX=(?:(?![" ]{{ item.key | regex_escape }}=).)*)(?:[" ]{{ item.key | regex_escape }}=\S+)?(.*")$'
            replace: '\1 {{ item.key }}={{ item.value }}\2'
          with_dict: "{{ grub_config }}"
          vars:
            grub_config:
              apparmor: "0"
              mitigations: "off"
          register: grub_status
        - name: System Configuration | Grub (2) # noqa: no-changed-when no-handler
          ansible.builtin.command: update-grub
          when: grub_status.changed

  handlers:
    - name: Reboot
      ansible.builtin.reboot:
        msg: Rebooting nodes
        reboot_timeout: 3600