diff --git a/ansible/inventory/host_vars/pve01.yml b/ansible/inventory/host_vars/pve01.yml new file mode 100644 index 0000000..75f3b59 --- /dev/null +++ b/ansible/inventory/host_vars/pve01.yml @@ -0,0 +1,27 @@ +--- +# Host-specific variables for pve01 +# IP: 10.0.0.201 + +# Hardware Details +hardware: + platform: physical_server + role: hypervisor + architecture: x86_64 + +# Operating System +os: + distribution: Proxmox VE + type: debian_based + +# Node Role +node_role: proxmox_hypervisor +is_hypervisor: true + +# Proxmox Configuration +proxmox: + post_install_enabled: true + disable_subscription_nag: true + disable_enterprise_repo: true + enable_no_subscription_repo: true + run_dist_upgrade: false # Manual control for first onboarding + reboot_after: false # Manual control for first onboarding diff --git a/ansible/inventory/hosts.ini b/ansible/inventory/hosts.ini index e85a0b5..ad5874a 100644 --- a/ansible/inventory/hosts.ini +++ b/ansible/inventory/hosts.ini @@ -25,6 +25,9 @@ waldorf ansible_host=10.0.0.251 ansible_user=chester # ============================================================================= # Platform Groups # ============================================================================= +[proxmox_cluster] +pve01 ansible_host=10.0.0.201 ansible_user=root + [physical_servers] heimdall ansible_host=10.0.0.151 ansible_user=chester waldorf ansible_host=10.0.0.251 ansible_user=chester diff --git a/ansible/playbooks/onboard-nodes.yml b/ansible/playbooks/onboard-nodes.yml index 6de1403..c59e3bc 100644 --- a/ansible/playbooks/onboard-nodes.yml +++ b/ansible/playbooks/onboard-nodes.yml @@ -27,7 +27,7 @@ - name: Ensure .ssh directory exists ansible.builtin.file: - path: "{{ ansible_env.HOME }}/.ssh" + path: "/home/{{ ansible_user }}/.ssh" state: directory mode: "0700" owner: "{{ ansible_user }}" @@ -88,7 +88,7 @@ ansible.builtin.debug: msg: >- {% if nfs_mount.stat.exists %} - ✅ /mnt/appdata exists ({{ 'mounted' if nfs_mount.stat.ismount else 'not mounted' }}) + ✅ /mnt/appdata exists {% else %} ⚠️ /mnt/appdata does NOT exist {% endif %} diff --git a/ansible/playbooks/onboard-proxmox.yml b/ansible/playbooks/onboard-proxmox.yml new file mode 100644 index 0000000..2011de0 --- /dev/null +++ b/ansible/playbooks/onboard-proxmox.yml @@ -0,0 +1,86 @@ +--- +# Proxmox Node Onboarding Playbook +# Purpose: Onboard Proxmox VE hosts with post-install configuration +# Usage: ansible-playbook playbooks/onboard-proxmox.yml -k --limit pve01 +# (-k prompts for root SSH password on first run) + +- name: Onboard Proxmox VE node + hosts: proxmox_cluster + gather_facts: true + become: false # Already connecting as root + + tasks: + - name: Display target host information + ansible.builtin.debug: + msg: | + Onboarding {{ inventory_hostname }} + IP: {{ ansible_host }} + User: {{ ansible_user }} + + - name: Ensure .ssh directory exists for root + ansible.builtin.file: + path: /root/.ssh + state: directory + mode: "0700" + owner: root + group: root + + - name: Deploy watchtower SSH public key to root + ansible.builtin.authorized_key: + user: root + state: present + key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ9ryXcRsMITcIW+Rc0t3Qou7XGfyIeihLR2PInySogp ansible@watchtower" + comment: "ansible@watchtower" + + - name: Detect Proxmox VE version + ansible.builtin.command: pveversion + register: pve_version_check + changed_when: false + failed_when: false + + - name: Display Proxmox version + ansible.builtin.debug: + msg: | + {% if pve_version_check.rc == 0 %} + ✅ Proxmox VE detected: {{ pve_version_check.stdout }} + {% else %} + ⚠️ Could not detect Proxmox VE (pveversion command failed) + {% endif %} + + - name: Verify Python 3 is available + ansible.builtin.command: python3 --version + register: python_version + changed_when: false + + - name: Display Python version + ansible.builtin.debug: + msg: "Python: {{ python_version.stdout }}" + + - name: Run Proxmox post-install configuration + ansible.builtin.include_role: + name: proxmox_post_install + vars: + proxmox_post_install_enabled: true + proxmox_disable_subscription_nag: true + proxmox_disable_pve_enterprise: true + proxmox_enable_pve_no_subscription: true + proxmox_fix_sources: true + proxmox_fix_ceph_repos: true + proxmox_run_dist_upgrade: false # Skip for initial onboarding + proxmox_reboot_after: false # Manual control + when: pve_version_check.rc == 0 + + - name: Display onboarding summary + ansible.builtin.debug: + msg: + - "==========================================" + - "Proxmox Onboarding Complete: {{ inventory_hostname }}" + - "==========================================" + - "✅ SSH key deployed to root" + - "✅ Subscription nag removed" + - "✅ Repositories configured" + - "" + - "Next steps:" + - " • Test connectivity: ansible pve01 -m ping" + - " • Update system: ansible pve01 -m apt -a 'upgrade=dist update_cache=yes'" + - " • Review logs and reboot if kernel/system updates applied" diff --git a/ansible/roles/proxmox_post_install/defaults/main.yml b/ansible/roles/proxmox_post_install/defaults/main.yml new file mode 100644 index 0000000..03aec6b --- /dev/null +++ b/ansible/roles/proxmox_post_install/defaults/main.yml @@ -0,0 +1,32 @@ +--- +# Default variables for proxmox_post_install role +# These defaults assume you "approve all risks" similar to the original script + +# General +proxmox_post_install_enabled: true + +# Behavior toggles roughly mirroring the whiptail prompts +proxmox_fix_sources: true +proxmox_disable_pve_enterprise: true +proxmox_enable_pve_no_subscription: true +proxmox_fix_ceph_repos: true +proxmox_add_pvetest_repo_disabled: true + +# Subscription nag removal +proxmox_disable_subscription_nag: true + +# HA behavior +proxmox_enable_ha: false # default: do not auto-enable HA on fresh node +proxmox_disable_ha_on_single_node: true +proxmox_disable_corosync_on_single_node: true + +# Update & reboot +proxmox_run_dist_upgrade: true +proxmox_reboot_after: true + +# PVE version restrictions (mirrors the script: 8.0-8.9.x and 9.0-9.1.x) +proxmox_supported_major_versions: [8, 9] +proxmox_8_min_minor: 0 +proxmox_8_max_minor: 9 +proxmox_9_min_minor: 0 +proxmox_9_max_minor: 1 diff --git a/ansible/roles/proxmox_post_install/tasks/main.yml b/ansible/roles/proxmox_post_install/tasks/main.yml new file mode 100644 index 0000000..1c7beaf --- /dev/null +++ b/ansible/roles/proxmox_post_install/tasks/main.yml @@ -0,0 +1,55 @@ +--- +# Main entrypoint for proxmox_post_install role + +- name: "Check that role is enabled" + ansible.builtin.meta: end_play + when: not proxmox_post_install_enabled + +- name: "Detect Proxmox VE version (pveversion)" + ansible.builtin.command: "pveversion" + register: proxmox_pveversion_cmd + changed_when: false + +- name: "Parse Proxmox VE version" + ansible.builtin.set_fact: + proxmox_pve_version_full: "{{ proxmox_pveversion_cmd.stdout | trim }}" + # pveversion output: "pve-manager/9.1.1/42db4a6cf33dac83" - version is at index 1 + proxmox_pve_version: "{{ (proxmox_pveversion_cmd.stdout | trim).split('/')[1] }}" + proxmox_pve_major: "{{ (proxmox_pveversion_cmd.stdout | trim).split('/')[1].split('.')[0] | int }}" + proxmox_pve_minor: "{{ (proxmox_pveversion_cmd.stdout | trim).split('/')[1].split('.')[1] | int }}" + +- name: "Fail if Proxmox VE major version is unsupported" + ansible.builtin.fail: + msg: >- + Unsupported Proxmox VE major version: {{ proxmox_pve_major }}. + Supported: 8.0–8.9.x and 9.0–9.1.x (mirrors upstream post-pve-install.sh). + when: proxmox_pve_major not in proxmox_supported_major_versions + +- name: "Fail if Proxmox VE 8 minor version unsupported" + ansible.builtin.fail: + msg: >- + Unsupported Proxmox 8 version {{ proxmox_pve_version }}. + Supported minor range: {{ proxmox_8_min_minor }}–{{ proxmox_8_max_minor }}. + when: + - proxmox_pve_major == 8 + - proxmox_pve_minor < proxmox_8_min_minor or proxmox_pve_minor > proxmox_8_max_minor + +- name: "Fail if Proxmox VE 9 minor version unsupported" + ansible.builtin.fail: + msg: >- + Unsupported Proxmox 9 version {{ proxmox_pve_version }}. + Supported minor range: {{ proxmox_9_min_minor }}–{{ proxmox_9_max_minor }}. + when: + - proxmox_pve_major == 9 + - proxmox_pve_minor < proxmox_9_min_minor or proxmox_pve_minor > proxmox_9_max_minor + +- name: "Include version-specific tasks for PVE 8" + ansible.builtin.import_tasks: pve8.yml + when: proxmox_pve_major == 8 + +- name: "Include version-specific tasks for PVE 9" + ansible.builtin.import_tasks: pve9.yml + when: proxmox_pve_major == 9 + +- name: "Common post-routines (nag, HA, update, reboot)" + ansible.builtin.import_tasks: post_common.yml diff --git a/ansible/roles/proxmox_post_install/tasks/post_common.yml b/ansible/roles/proxmox_post_install/tasks/post_common.yml new file mode 100644 index 0000000..6dde402 --- /dev/null +++ b/ansible/roles/proxmox_post_install/tasks/post_common.yml @@ -0,0 +1,76 @@ +--- +# Common post-routines for PVE 8 and 9: subscription nag, HA, updates, reboot + +- name: "Deploy subscription nag removal script" + ansible.builtin.template: + src: pve-remove-nag.sh.j2 + dest: /usr/local/bin/pve-remove-nag.sh + owner: root + group: root + mode: '0755' + when: proxmox_disable_subscription_nag + +- name: "Configure dpkg Post-Invoke hook to run nag removal script" + ansible.builtin.copy: + dest: /etc/apt/apt.conf.d/no-nag-script + owner: root + group: root + mode: '0644' + content: | + DPkg::Post-Invoke { "/usr/local/bin/pve-remove-nag.sh"; }; + when: proxmox_disable_subscription_nag + +- name: "Remove subscription nag dpkg hook if disabled via vars" + ansible.builtin.file: + path: /etc/apt/apt.conf.d/no-nag-script + state: absent + when: not proxmox_disable_subscription_nag + +- name: "Ensure proxmox-widget-toolkit is reinstalled (like script)" + ansible.builtin.apt: + name: proxmox-widget-toolkit + state: latest + update_cache: false + force: true + register: proxmox_widget_reinstall + failed_when: false + +- name: "Optionally enable HA services on cluster nodes" + ansible.builtin.service: + name: "{{ item }}" + state: started + enabled: true + loop: + - pve-ha-lrm + - pve-ha-crm + - corosync + when: proxmox_enable_ha + +- name: "Optionally disable HA services on single-node setups" + ansible.builtin.service: + name: "{{ item }}" + state: stopped + enabled: false + loop: + - pve-ha-lrm + - pve-ha-crm + when: proxmox_disable_ha_on_single_node + +- name: "Optionally disable Corosync on single-node setups" + ansible.builtin.service: + name: corosync + state: stopped + enabled: false + when: proxmox_disable_corosync_on_single_node + +- name: "Run apt dist-upgrade (like original script)" + ansible.builtin.apt: + update_cache: true + upgrade: dist + when: proxmox_run_dist_upgrade + +- name: "Reboot Proxmox VE when requested" + ansible.builtin.reboot: + msg: "Rebooting after post-install routines (Ansible)." + reboot_timeout: 1800 + when: proxmox_reboot_after diff --git a/ansible/roles/proxmox_post_install/tasks/pve8.yml b/ansible/roles/proxmox_post_install/tasks/pve8.yml new file mode 100644 index 0000000..2ef890a --- /dev/null +++ b/ansible/roles/proxmox_post_install/tasks/pve8.yml @@ -0,0 +1,57 @@ +--- +# Proxmox VE 8.x (Debian 12 / bookworm) sources and repo configuration + +- name: "Configure Debian bookworm APT sources (if enabled)" + ansible.builtin.copy: + dest: /etc/apt/sources.list + owner: root + group: root + mode: '0644' + content: | + deb http://deb.debian.org/debian bookworm main contrib + deb http://deb.debian.org/debian bookworm-updates main contrib + deb http://security.debian.org/debian-security bookworm-security main contrib + when: proxmox_fix_sources + +- name: "Disable pve-enterprise repository (list file) on 8.x" + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/pve-enterprise.list + owner: root + group: root + mode: '0644' + content: | + # deb https://enterprise.proxmox.com/debian/pve bookworm pve-enterprise + when: proxmox_disable_pve_enterprise + +- name: "Enable pve-no-subscription repository on 8.x" + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/pve-install-repo.list + owner: root + group: root + mode: '0644' + content: | + deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription + when: proxmox_enable_pve_no_subscription + +- name: "Configure Ceph repositories for Proxmox VE 8.x" + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/ceph.list + owner: root + group: root + mode: '0644' + content: | + # deb https://enterprise.proxmox.com/debian/ceph-quincy bookworm enterprise + # deb http://download.proxmox.com/debian/ceph-quincy bookworm no-subscription + # deb https://enterprise.proxmox.com/debian/ceph-reef bookworm enterprise + # deb http://download.proxmox.com/debian/ceph-reef bookworm no-subscription + when: proxmox_fix_ceph_repos + +- name: "Add disabled pvetest repository for 8.x" + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/pvetest-for-beta.list + owner: root + group: root + mode: '0644' + content: | + # deb http://download.proxmox.com/debian/pve bookworm pvetest + when: proxmox_add_pvetest_repo_disabled diff --git a/ansible/roles/proxmox_post_install/tasks/pve9.yml b/ansible/roles/proxmox_post_install/tasks/pve9.yml new file mode 100644 index 0000000..0849b01 --- /dev/null +++ b/ansible/roles/proxmox_post_install/tasks/pve9.yml @@ -0,0 +1,123 @@ +--- +# Proxmox VE 9.x (Debian 13 / trixie) sources and repo configuration using deb822 + +- name: "Find legacy .list APT source files on 9.x" + ansible.builtin.find: + paths: + - /etc/apt/sources.list.d + patterns: "*.list" + file_type: file + register: proxmox_legacy_list_files + +- name: "Backup and disable entries in /etc/apt/sources.list (if any)" + ansible.builtin.copy: + src: /etc/apt/sources.list + dest: /etc/apt/sources.list.bak + owner: root + group: root + mode: '0644' + remote_src: true + when: + - proxmox_fix_sources + - ansible_facts['os_family'] is defined + ignore_errors: true + +- name: "Comment legacy deb lines in /etc/apt/sources.list (bookworm/proxmox)" + ansible.builtin.replace: + path: /etc/apt/sources.list + regexp: '^(\s*deb\s+.*(proxmox|bookworm).*)$' + replace: '# Disabled by Proxmox Helper Ansible role \1' + when: proxmox_fix_sources + ignore_errors: true + +- name: "Remove legacy .list files on 9.x when migrating to deb822" + ansible.builtin.file: + path: "{{ item.path }}" + state: absent + loop: "{{ proxmox_legacy_list_files.files | default([]) }}" + when: proxmox_fix_sources + +- name: "Configure Debian Trixie deb822 sources for 9.x" + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/debian.sources + owner: root + group: root + mode: '0644' + content: | + Types: deb + URIs: http://deb.debian.org/debian + Suites: trixie + Components: main contrib + Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg + + Types: deb + URIs: http://security.debian.org/debian-security + Suites: trixie-security + Components: main contrib + Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg + + Types: deb + URIs: http://deb.debian.org/debian + Suites: trixie-updates + Components: main contrib + Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg + when: proxmox_fix_sources + +- name: "Ensure pve-enterprise deb822 source is disabled on 9.x" + ansible.builtin.blockinfile: + path: /etc/apt/sources.list.d/pve-enterprise.sources + create: true + owner: root + group: root + mode: '0644' + block: | + Types: deb + URIs: https://enterprise.proxmox.com/debian/pve + Suites: trixie + Components: pve-enterprise + Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg + Enabled: false + when: proxmox_disable_pve_enterprise + +- name: "Configure pve-no-subscription deb822 source on 9.x" + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/proxmox.sources + owner: root + group: root + mode: '0644' + content: | + Types: deb + URIs: http://download.proxmox.com/debian/pve + Suites: trixie + Components: pve-no-subscription + Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg + when: proxmox_enable_pve_no_subscription + +- name: "Configure Ceph deb822 source on 9.x (no-subscription)" + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/ceph.sources + owner: root + group: root + mode: '0644' + content: | + Types: deb + URIs: http://download.proxmox.com/debian/ceph-squid + Suites: trixie + Components: no-subscription + Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg + when: proxmox_fix_ceph_repos + +- name: "Add disabled pve-test deb822 source on 9.x" + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/pve-test.sources + owner: root + group: root + mode: '0644' + content: | + Types: deb + URIs: http://download.proxmox.com/debian/pve + Suites: trixie + Components: pve-test + Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg + Enabled: false + when: proxmox_add_pvetest_repo_disabled diff --git a/ansible/roles/proxmox_post_install/templates/pve-remove-nag.sh.j2 b/ansible/roles/proxmox_post_install/templates/pve-remove-nag.sh.j2 new file mode 100644 index 0000000..de1271f --- /dev/null +++ b/ansible/roles/proxmox_post_install/templates/pve-remove-nag.sh.j2 @@ -0,0 +1,45 @@ +#!/bin/sh +WEB_JS=/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js +if [ -s "$WEB_JS" ] && ! grep -q NoMoreNagging "$WEB_JS"; then + echo "Patching Web UI nag..." + sed -i -e "/data\.status/ s/!//" -e "/data\.status/ s/active/NoMoreNagging/" "$WEB_JS" +fi + +MOBILE_TPL=/usr/share/pve-yew-mobile-gui/index.html.tpl +MARKER="" +if [ -f "$MOBILE_TPL" ] && ! grep -q "$MARKER" "$MOBILE_TPL"; then + echo "Patching Mobile UI nag..." + printf "%s\n" \ + "$MARKER" \ + "" \ + "" >>"$MOBILE_TPL" +fi