From 67613c009d0ee112f394f0965feea4a633e331bd Mon Sep 17 00:00:00 2001 From: Vezpi Date: Wed, 3 Jun 2026 18:20:15 +0000 Subject: [PATCH] add: update Proxmox VE playbook --- ansible/proxmox/update_proxmox.yml | 209 +++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 ansible/proxmox/update_proxmox.yml diff --git a/ansible/proxmox/update_proxmox.yml b/ansible/proxmox/update_proxmox.yml new file mode 100644 index 0000000..1c38f36 --- /dev/null +++ b/ansible/proxmox/update_proxmox.yml @@ -0,0 +1,209 @@ +--- +- name: Rolling update Proxmox VE cluster + hosts: nodes + any_errors_fatal: true + become: true + serial: 1 + + pre_tasks: + + ########################################################## + # Verify input variables + ########################################################## + + - name: Assert ntfy variables + ansible.builtin.assert: + that: + - ntfy_topic is defined + - ntfy_user is defined + - ntfy_password is defined + quiet: true + when: ntfy_url is defined + + ########################################################## + # Verify cluster health + ########################################################## + + - name: Verify quorum + ansible.builtin.command: pvecm status + register: quorum_status + changed_when: false + delegate_to: "{{ groups['nodes'][0] }}" + run_once: true + + - name: Abort if cluster has no quorum + ansible.builtin.fail: + msg: "Cluster quorum not available" + when: "'Quorate: Yes' not in quorum_status.stdout" + + - name: Check Ceph health + ansible.builtin.command: ceph health + register: ceph_health + changed_when: false + delegate_to: "{{ groups['nodes'][0] }}" + run_once: true + + - name: Abort if Ceph unhealthy + ansible.builtin.fail: + msg: "{{ ceph_health.stdout }}" + when: "'HEALTH_OK' not in ceph_health.stdout" + + tasks: + + - block: + + ########################################################## + # Capture current versions + ########################################################## + + - name: Capture version after upgrade + ansible.builtin.command: pveversion | awk -F'/' '{print $2}' + register: pve_current_version + changed_when: false + + ########################################################## + # Enable maintenance mode + ########################################################## + + - name: Enable maintenance mode + ansible.builtin.command: > + ha-manager crm-command node-maintenance enable {{ inventory_hostname }} + + ########################################################## + # Wait until node empty + ########################################################## + + - name: Wait for VMs to leave node + ansible.builtin.shell: | + qm list | awk 'NR>1 && $3=="running" {count++} END {print count+0}' + register: vm_count + changed_when: false + until: vm_count.stdout | int == 0 + retries: 60 + delay: 15 + + - name: Wait for LXCs to leave node + ansible.builtin.shell: | + pct list | awk 'NR>1 && $2=="running" {count++} END {print count+0}' + register: lxc_count + changed_when: false + until: lxc_count.stdout | int == 0 + retries: 60 + delay: 15 + + ########################################################## + # Upgrade packages + ########################################################## + + - name: Refresh repositories + ansible.builtin.apt: + update_cache: true + + - name: Dist upgrade + ansible.builtin.apt: + upgrade: dist + autoremove: true + autoclean: true + + ########################################################## + # Capture new versions + ########################################################## + + - name: Capture version after upgrade + ansible.builtin.command: pveversion | awk -F'/' '{print $2}' + register: pve_new_version + changed_when: false + + ########################################################## + # Check reboot with Ceph rebalancing disabled + ########################################################## + + - name: Check reboot requirement + ansible.builtin.stat: + path: /var/run/reboot-required + register: reboot_required + + - when: reboot_required.stat.exists + block: + - name: Disable Ceph rebalancing + ansible.builtin.command: ceph osd set noout + + - name: Reboot node + ansible.builtin.reboot: + reboot_timeout: 900 + post_reboot_delay: 30 + + - name: Wait for connection + ansible.builtin.wait_for_connection: + timeout: 600 + + - name: Enable Ceph rebalancing + ansible.builtin.command: ceph osd unset noout + + ########################################################## + # Ceph validation + ########################################################## + + - name: Wait for HEALTH_OK + ansible.builtin.command: ceph health + register: ceph_status + changed_when: false + until: "'HEALTH_OK' in ceph_status.stdout" + retries: 60 + delay: 15 + delegate_to: "{{ groups['nodes'][0] }}" + + ########################################################## + # Disable maintenance mode + ########################################################## + + - name: Disable maintenance mode + ansible.builtin.command: > + ha-manager crm-command node-maintenance disable {{ inventory_hostname }} + + rescue: + + ########################################################## + # Send notification + ########################################################## + + - name: Send failure notification + ansible.builtin.uri: + url: "{{ ntfy_url }}/{{ ntfy_topic }}" + method: POST + user: "{{ ntfy_user }}" + password: "{{ ntfy_password }}" + force_basic_auth: true + body: Update failed on {{ inventory_hostname }} + headers: + Title: "Proxmox cluster update failed" + Priority: "5" + Tags: "x" + delegate_to: localhost + run_once: true + when: ntfy_url is defined + + - ansible.builtin.fail: + msg: "Update aborted" + + post_tasks: + + - name: Send success notification + ansible.builtin.uri: + url: "{{ ntfy_url }}/{{ ntfy_topic }}" + method: POST + user: "{{ ntfy_user }}" + password: "{{ ntfy_password }}" + force_basic_auth: true + body: | + Proxmox cluster update completed successfully. + Old version: {{ pve_current_version.stdout }} + New version: {{ pve_new_version.stdout }} + headers: + Title: "Proxmox Update" + Priority: "3" + Tags: "white_check_mark" + delegate_to: localhost + run_once: true + when: ntfy_url is defined +