my-homelab-configs/bootstrap/host/playbook.yml

251 lines
9.2 KiB
YAML

---
- name: Restore Debian homelab control-plane and desktop host
hosts: debian_pc
become: true
gather_facts: true
pre_tasks:
- name: Require Debian
ansible.builtin.assert:
that:
- ansible_facts.os_family == "Debian"
- ansible_facts.distribution == "Debian"
fail_msg: "This host bootstrap is intentionally scoped to Debian."
- name: Install apt prerequisites
ansible.builtin.apt:
name: "{{ debian_pc_base_packages }}"
state: present
update_cache: true
- name: Ensure apt keyring directory exists
ansible.builtin.file:
path: /etc/apt/keyrings
state: directory
mode: "0755"
tasks:
- name: Add Docker apt key
ansible.builtin.get_url:
url: https://download.docker.com/linux/debian/gpg
dest: /etc/apt/keyrings/docker.asc
mode: "0644"
- name: Add Docker apt source
ansible.builtin.copy:
dest: /etc/apt/sources.list.d/docker.sources
mode: "0644"
content: |
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: {{ ansible_facts.distribution_release }}
Components: stable
Architectures: {{ ansible_facts.architecture | regex_replace('x86_64', 'amd64') | regex_replace('aarch64', 'arm64') }}
Signed-By: /etc/apt/keyrings/docker.asc
- name: Add Kubernetes apt key
ansible.builtin.shell: |
set -euo pipefail
curl -fsSL "https://pkgs.k8s.io/core:/stable:/{{ debian_pc_kubernetes_minor_version }}/deb/Release.key" |
gpg --dearmor >/etc/apt/keyrings/kubernetes-apt-keyring.gpg
chmod 0644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
args:
executable: /bin/bash
creates: /etc/apt/keyrings/kubernetes-apt-keyring.gpg
- name: Add Kubernetes apt source
ansible.builtin.copy:
dest: /etc/apt/sources.list.d/kubernetes.list
mode: "0644"
content: |
deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/{{ debian_pc_kubernetes_minor_version }}/deb/ /
- name: Add Helm apt key
ansible.builtin.shell: |
set -euo pipefail
helm_key_fingerprint="DDF78C3E6EBB2D2CC223C95C62BA89D07698DBC6"
tmp_key="$(mktemp)"
trap 'rm -f "${tmp_key}"' EXIT
curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey >"${tmp_key}"
actual_fingerprint="$(gpg --show-keys --with-colons "${tmp_key}" | awk -F: '$1 == "fpr" { print $10; exit }')"
if [ "${actual_fingerprint}" != "${helm_key_fingerprint}" ]; then
echo "Unexpected Helm apt key fingerprint: ${actual_fingerprint}" >&2
exit 1
fi
gpg --dearmor <"${tmp_key}" >/etc/apt/keyrings/helm.gpg
chmod 0644 /etc/apt/keyrings/helm.gpg
args:
executable: /bin/bash
creates: /etc/apt/keyrings/helm.gpg
- name: Add Helm apt source
ansible.builtin.copy:
dest: /etc/apt/sources.list.d/helm-stable-debian.list
mode: "0644"
content: |
deb [arch={{ ansible_facts.architecture | regex_replace('x86_64', 'amd64') | regex_replace('aarch64', 'arm64') }} signed-by=/etc/apt/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main
- name: Add OpenTofu apt keys
ansible.builtin.shell: |
set -euo pipefail
curl -fsSL https://get.opentofu.org/opentofu.gpg >/etc/apt/keyrings/opentofu.gpg
curl -fsSL https://packages.opentofu.org/opentofu/tofu/gpgkey |
gpg --dearmor >/etc/apt/keyrings/opentofu-repo.gpg
chmod 0644 /etc/apt/keyrings/opentofu.gpg /etc/apt/keyrings/opentofu-repo.gpg
args:
executable: /bin/bash
creates: /etc/apt/keyrings/opentofu-repo.gpg
- name: Add OpenTofu apt source
ansible.builtin.copy:
dest: /etc/apt/sources.list.d/opentofu.list
mode: "0644"
content: |
deb [signed-by=/etc/apt/keyrings/opentofu.gpg,/etc/apt/keyrings/opentofu-repo.gpg] https://packages.opentofu.org/opentofu/tofu/any/ any main
- name: Add Brave apt key
ansible.builtin.get_url:
url: https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg
dest: /etc/apt/keyrings/brave-browser-archive-keyring.gpg
mode: "0644"
- name: Add Brave apt source
ansible.builtin.copy:
dest: /etc/apt/sources.list.d/brave-browser-release.sources
mode: "0644"
content: |
Types: deb
URIs: https://brave-browser-apt-release.s3.brave.com/
Suites: stable
Components: main
Architectures: amd64 arm64
Signed-By: /etc/apt/keyrings/brave-browser-archive-keyring.gpg
- name: Refresh apt cache after repository setup
ansible.builtin.apt:
update_cache: true
- name: Write desired package list for availability filtering
ansible.builtin.copy:
dest: /tmp/homelab-debian-pc-desired-packages.txt
mode: "0644"
content: |
{% for package in (debian_pc_base_packages + debian_pc_apt_manual_packages) | unique | sort %}
{{ package }}
{% endfor %}
- name: Filter packages available to apt
ansible.builtin.shell: |
set -euo pipefail
while IFS= read -r package; do
[ -n "$package" ] || continue
if apt-cache policy "$package" | awk '/Candidate:/ && $2 != "(none)" { found = 1 } END { exit found ? 0 : 1 }'; then
printf '%s\n' "$package"
fi
done </tmp/homelab-debian-pc-desired-packages.txt
args:
executable: /bin/bash
register: debian_pc_installable_packages_result
changed_when: false
- name: Track installable package list
ansible.builtin.set_fact:
debian_pc_installable_packages: "{{ debian_pc_installable_packages_result.stdout_lines | default([]) }}"
- name: Install available Debian PC packages
ansible.builtin.apt:
name: "{{ debian_pc_installable_packages }}"
state: present
when: debian_pc_installable_packages | length > 0
- name: Install Zoom from upstream deb when requested on amd64
ansible.builtin.apt:
deb: https://zoom.us/client/latest/zoom_amd64.deb
state: present
when:
- "'zoom' in debian_pc_apt_manual_packages"
- ansible_facts.architecture == "x86_64"
- name: Hold Kubernetes and runtime packages
ansible.builtin.dpkg_selections:
name: "{{ item }}"
selection: hold
loop: "{{ debian_pc_hold_packages }}"
failed_when: false
- name: Ensure expected local groups exist
ansible.builtin.group:
name: "{{ item }}"
state: present
loop: "{{ debian_pc_user_groups }}"
- name: Ensure user supplementary groups
ansible.builtin.user:
name: "{{ debian_pc_user }}"
groups: "{{ debian_pc_user_groups }}"
append: true
- name: Allow passwordless sudo for homelab automation
ansible.builtin.copy:
dest: "/etc/sudoers.d/90-homelab-{{ debian_pc_user }}"
owner: root
group: root
mode: "0440"
validate: "visudo -cf %s"
content: |
{{ debian_pc_user }} ALL=(ALL) NOPASSWD:ALL
when: debian_pc_enable_passwordless_sudo | bool
- name: Ensure persistent homelab directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ debian_pc_user if item.startswith(debian_pc_user_home) else 'root' }}"
group: "{{ debian_pc_user if item.startswith(debian_pc_user_home) else 'root' }}"
mode: "{{ '0755' if item.startswith(debian_pc_user_home) else '0775' }}"
loop: "{{ debian_pc_persistent_directories }}"
- name: Enable expected services when installed
ansible.builtin.systemd:
name: "{{ item }}"
enabled: true
state: started
loop: "{{ debian_pc_enable_services }}"
failed_when: false
- name: Check whether config archive is present
ansible.builtin.stat:
path: "{{ debian_pc_config_archive }}"
register: debian_pc_config_archive_stat
when:
- debian_pc_restore_configs | bool
- debian_pc_config_archive | length > 0
- name: Restore captured home application configs
ansible.builtin.unarchive:
src: "{{ debian_pc_config_archive }}"
dest: "{{ debian_pc_user_home }}"
remote_src: true
owner: "{{ debian_pc_user }}"
group: "{{ debian_pc_user }}"
when:
- debian_pc_restore_configs | bool
- debian_pc_config_archive | length > 0
- debian_pc_config_archive_stat.stat.exists | default(false)
- name: Report packages skipped because apt has no candidate
ansible.builtin.shell: |
set -euo pipefail
comm -23 \
<(sort -u /tmp/homelab-debian-pc-desired-packages.txt) \
<(printf '%s\n' {{ debian_pc_installable_packages | map('quote') | join(' ') }} | sort -u)
args:
executable: /bin/bash
register: debian_pc_skipped_packages_result
changed_when: false
- name: Show skipped packages
ansible.builtin.debug:
msg: "{{ debian_pc_skipped_packages_result.stdout_lines }}"
when: debian_pc_skipped_packages_result.stdout_lines | length > 0