Files
homelab-infra/infrastructure/proxmox/ansible/roles/pve_vm/tasks/image.yml
T
panxiao81 88a02ababa
lint / yaml (push) Has been cancelled
lint / ansible (push) Has been cancelled
lint / terraform (push) Has been cancelled
Establish clean homelab infrastructure baseline
Reorganize the brownfield repository, remove retired and generated artifacts, harden ignore rules, and record the GitOps/IaC redesign.
2026-09-09 16:47:20 +00:00

68 lines
2.6 KiB
YAML

---
# Write a base image onto a freshly created VM disk.
#
# ⚠️ Deliberately NOT `qm importdisk`. On this LINSTOR/DRBD storage it reported
# success ("transferred 3.5 GiB", exit 0) but left ZEROS where the partition
# table belongs, producing a silently unbootable disk. `qemu-img convert`
# straight to the DRBD device works and takes ~40s. (Verified 2026-07-25.)
#
# Also note: the source is named *.img.raw but is actually QCOW2 — always let
# qemu detect the format rather than trusting the extension.
- name: Resolve the DRBD device backing the VM disk
ansible.builtin.shell:
cmd: |
set -o pipefail
# scsi0: <storage>:<volume>,opts... -> we want <volume>, i.e. field 3
vol=$(qm config {{ item.vmid }} | sed -n 's/^scsi0: *[^:]*:\([^,]*\).*/\1/p')
# PVE's volume is pm-xxxx_<vmid>, but the LINSTOR RESOURCE is just
# pm-xxxx -- strip the _<vmid> suffix or nothing ever matches.
res=${vol%_*}
linstor resource list-volumes 2>/dev/null \
| awk -v v="$res" -v n="$(hostname)" '$0 ~ v && $0 ~ n {print}' \
| grep -oE '/dev/drbd[0-9]+' | head -1
executable: /bin/bash
register: _drbd_dev
changed_when: false
delegate_to: "{{ pve_vm_node }}"
- name: Fail if the device could not be resolved
ansible.builtin.fail:
msg: "Could not find the DRBD device for VM {{ item.vmid }} scsi0 — refusing to write an image blind."
delegate_to: "{{ pve_vm_node }}"
when: (_drbd_dev.stdout | trim) | length == 0
- name: Check whether the disk already has a partition table
# Idempotency guard: never overwrite a disk that already looks installed.
ansible.builtin.shell:
cmd: |
python3 -c "
import sys
try:
d=open('{{ _drbd_dev.stdout | trim }}','rb').read(512)
sys.stdout.write('yes' if d[510:512]==b'\x55\xaa' else 'no')
except Exception:
sys.stdout.write('unreadable')"
executable: /bin/bash
register: _has_mbr
changed_when: false
delegate_to: "{{ pve_vm_node }}"
- name: Write the base image
# DRBD must be Primary to accept writes; reading a Secondary returns ZEROS,
# which is its own excellent way to misdiagnose an empty disk.
ansible.builtin.shell:
cmd: |
set -e
drbdadm primary {{ _res }} 2>/dev/null || true
qemu-img convert -O raw "{{ item.image }}" "{{ _dev }}"
sync
drbdadm secondary {{ _res }} 2>/dev/null || true
executable: /bin/bash
vars:
_dev: "{{ _drbd_dev.stdout | trim }}"
_res: "{{ _drbd_dev.stdout | trim | regex_replace('.*drbd', '') }}"
when: _has_mbr.stdout is not search('yes')
changed_when: true
delegate_to: "{{ pve_vm_node }}"