Fix snapshot role — XO REST API, fix playbook host targeting

- roles/snapshot/tasks/main.yml: replace xe CLI with XO REST API
  - POST /rest/v0/vms/<uuid>/actions/snapshot?sync=true
  - stores returned snapshot UUID as snapshot_id
  - baremetal: skips gracefully with warning
- playbooks/snapshot_pre.yml: target linux_hosts only (was all)
- playbooks/linux_patch.yml: remove snapshot + report roles (snapshot is separate step)
- playbooks/site_maintenance.yml: remove bootstrap play (handled per-playbook),
  remove windows_patch import (WinRM not implemented)
This commit is contained in:
Semaphore
2026-03-12 21:44:20 -07:00
parent 72126525ea
commit ca0f11b1c9
4 changed files with 97 additions and 51 deletions

View File

@@ -1,13 +1,32 @@
---
# =============================================================================
# roles/snapshot/tasks/main.yml
#
# Creates pre-patch snapshots for guest VMs.
# Runs against linux_hosts — each host needs xcpng_vm_uuid or proxmox_vmid set.
#
# Hypervisor dispatch:
# proxmox → community.general.proxmox_snap (delegate_to: localhost)
# xcpng → XO REST API snapshot action (delegate_to: localhost)
# baremetal → skipped entirely
#
# Required vars:
# XCP-NG: xcpng_vm_uuid, XO_URL, XO_TOKEN (from variable group)
# Proxmox: proxmox_vmid, PROXMOX_HOST, PROXMOX_TOKEN_ID, PROXMOX_TOKEN_SECRET
# =============================================================================
# ─── Proxmox snapshots ────────────────────────────────────────────────────────
- name: Create pre-patch snapshot (Proxmox)
community.general.proxmox_snap:
api_host: "{{ PROXMOX_HOST }}"
api_user: "{{ PROXMOX_TOKEN_ID | split('!') | first }}"
api_token_id: "{{ PROXMOX_TOKEN_ID | split('!') | last }}"
api_host: "{{ PROXMOX_HOST }}"
api_user: "{{ PROXMOX_TOKEN_ID | split('!') | first }}"
api_token_id: "{{ PROXMOX_TOKEN_ID | split('!') | last }}"
api_token_secret: "{{ PROXMOX_TOKEN_SECRET }}"
vmid: "{{ proxmox_vmid }}"
state: present
snapname: "{{ snapshot_name_prefix }}-{{ ansible_date_time.date }}-{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}"
vmid: "{{ proxmox_vmid }}"
state: present
snapname: >-
{{ snapshot_name_prefix }}-{{ ansible_date_time.date }}-{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}
description: "Ansible pre-patch snapshot {{ ansible_date_time.iso8601 }}"
register: proxmox_snapshot_result
when: hypervisor_type == "proxmox"
@@ -15,52 +34,60 @@
- name: Store Proxmox snapshot name
ansible.builtin.set_fact:
snapshot_id: "{{ snapshot_name_prefix }}-{{ ansible_date_time.date }}-{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}"
snapshot_id: >-
{{ snapshot_name_prefix }}-{{ ansible_date_time.date }}-{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}
when: hypervisor_type == "proxmox"
- name: Create pre-patch snapshot (XCP-NG)
ansible.builtin.shell: |
xe vm-snapshot vm={{ xcpng_vm_uuid }} new-name-label="{{ snapshot_name_prefix }}-{{ ansible_date_time.date }}-{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}"
# ─── XCP-NG snapshots via XO REST API ────────────────────────────────────────
- name: Create pre-patch snapshot (XCP-NG via XO REST API)
ansible.builtin.uri:
url: "{{ XO_URL }}/rest/v0/vms/{{ xcpng_vm_uuid }}/actions/snapshot?sync=true"
method: POST
headers:
Cookie: "authenticationToken={{ XO_TOKEN }}"
Content-Type: "application/json"
Accept: "application/json"
body_format: json
body:
name_label: >-
{{ snapshot_name_prefix }}-{{ ansible_date_time.date }}-{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}
validate_certs: "{{ xo_validate_certs | default(true) }}"
status_code: [200, 201]
timeout: 120
register: xcpng_snapshot_result
changed_when: xcpng_snapshot_result.rc == 0
when: hypervisor_type == "xcpng" and xcpng_host | length > 0
delegate_to: "{{ xcpng_host if xcpng_host | length > 0 else 'localhost' }}"
when: hypervisor_type == "xcpng" or hypervisor_type == "mixed"
delegate_to: localhost
- name: Store XCP-NG snapshot UUID
ansible.builtin.set_fact:
snapshot_id: "{{ xcpng_snapshot_result.stdout | trim }}"
when: hypervisor_type == "xcpng"
snapshot_id: "{{ xcpng_snapshot_result.json | regex_replace('\"', '') }}"
when:
- hypervisor_type == "xcpng" or hypervisor_type == "mixed"
- xcpng_snapshot_result is not skipped
- xcpng_snapshot_result.json is defined
- name: Verify snapshot was created (Proxmox)
community.general.proxmox_snap:
api_host: "{{ PROXMOX_HOST }}"
api_user: "{{ PROXMOX_TOKEN_ID | split('!') | first }}"
api_token_id: "{{ PROXMOX_TOKEN_ID | split('!') | last }}"
api_token_secret: "{{ PROXMOX_TOKEN_SECRET }}"
vmid: "{{ proxmox_vmid }}"
snapname: "{{ snapshot_id }}"
state: present
register: proxmox_snap_verify
when: hypervisor_type == "proxmox"
delegate_to: localhost
# ─── Verify and assert ───────────────────────────────────────────────────────
- name: Verify snapshot was created (XCP-NG)
ansible.builtin.shell: |
xe snapshot-list uuid={{ snapshot_id }} | grep uuid
register: xcpng_snap_verify
changed_when: false
failed_when: xcpng_snap_verify.stdout == ""
when: hypervisor_type == "xcpng" and xcpng_host | length > 0
delegate_to: "{{ xcpng_host if xcpng_host | length > 0 else 'localhost' }}"
- name: Assert snapshot exists before proceeding
- name: Assert snapshot was created
ansible.builtin.assert:
that:
- snapshot_id is defined
- snapshot_id != ""
fail_msg: "SNAPSHOT: Failed to create or verify snapshot for {{ inventory_hostname }}. Aborting patch run."
success_msg: "Snapshot verified: {{ snapshot_id }}"
- snapshot_id | length > 0
fail_msg: >-
SNAPSHOT FAILED: Could not create or verify snapshot for {{ inventory_hostname }}.
Aborting to protect against unsnapshotted patch run.
success_msg: "Snapshot OK: {{ snapshot_id }} for {{ inventory_hostname }}"
when: hypervisor_type != "baremetal"
- name: Log snapshot ID
- name: Log snapshot result
ansible.builtin.debug:
msg: "Pre-patch snapshot created: {{ snapshot_id }} for {{ inventory_hostname }}"
when: hypervisor_type != "baremetal"
- name: Log snapshot skipped (baremetal)
ansible.builtin.debug:
msg: >-
Snapshot skipped for {{ inventory_hostname }} — hypervisor_type is baremetal.
Ensure change approval is in place before patching.
when: hypervisor_type == "baremetal"