Backup VM-level de Nutanix AHV vía Prism v3+v4 con Changed Regions Tracking nativo, replicación vendor-neutral PHCBT01, cross-hypervisor inbound desde Proxmox/vSphere/Hyper-V y disk-only / alternate-cluster restore — todos ausentes del plugin AHV de Bacula Enterprise 18.2.3.
Documento técnico complementario a la página del plugin PodHeitor Nutanix.
1. Lagunas del plugin Nutanix de Bacula Enterprise
Bacula Enterprise 18.2.3 incluye un plugin Nutanix AHV — basado en JVM, Prism v2/v3, sin CRT v4, sin cross-restore, sin replicación vendor-neutral, sin disk-only restore, sin alternate-cluster restore. Para clientes que corren pc.2024.3+ y quieren DR multi-vendor, eso deja cuatro lagunas operacionales grandes:
- Sin CRT v4. La API
compute-changed-regionsen pc.2024.3+ es más rápida y granular que el legado v3changed_regions. BEE no la consume. - Sin cross-restore. Backup AHV restaura solo en AHV. Salir de Nutanix exige V2V manual.
- Replicación acoplada a Nutanix Protection Policies. No funciona cross-vendor.
- Latencia JVM. Pausas GC durante streaming de discos grandes son mensurables.
El PodHeitor Nutanix Plugin es un sibling Rust de los plugins podheitor-proxmox, podheitor-vsphere e podheitor-hyperv — reusando sus formatos on-wire byte-a-byte para que los restores sean totalmente cross-compatibles.
2. Modelo arquitectónico — two-process Rust
El plugin sigue el patrón PodHeitor: cdylib (en este caso un shim C++ de ~120 LOC, constants-only, linkeado contra el metaplugin framework) + backend Rust standalone, comunicándose vía PTCOMM length-tagged framing en stdin/stdout.
┌──────────────────────────────────────────────────────────────────────────┐
│ Bacula File Daemon (bacula-fd) │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ podheitor-nutanix-fd.so (metaplugin C++ shim, ~120 LOC) │ │
│ │ - PLUGINNAMESPACE="@nutanix" │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │ PTCOMM over pipe (stdin/stdout) │
└──────────────────────────────┼────────────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ podheitor-nutanix-backend (Rust binary) │
│ ┌──────────────┬──────────────┬──────────────┬──────────────────────┐ │
│ │ prism v3/v4 │ snapshot │ iscsi │ disk_reader │ │
│ │ REST client │ RAII guard │ attach/detach│ (O_DIRECT /dev/sdX) │ │
│ ├──────────────┼──────────────┼──────────────┼──────────────────────┤ │
│ │ crt (CBT) │ backup.rs │ restore.rs │ replication.rs │ │
│ └──────────────┴──────────────┴──────────────┴──────────────────────┘ │
└────┬─────────────────────────┬────────────────────────┬───────────────────┘
│ HTTPS (9440) │ iSCSI (DSIP:3260) │ TLS (9848)
▼ ▼ ▼
┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Prism Central│ │ Nutanix CVMs │ │ DR Receiver │
└──────────────┘ └──────────────────┘ └──────────────────┘
2.1 Dos modos de despliegue, un binario
| Mode | Dónde corre el backend | Cuándo elegir |
|---|---|---|
proxy_mode=external |
FD host fuera del cluster AHV | Default — exige ruta de red a Prism:9440 + DSIP:3260 y open-iscsi en el FD host |
proxy_mode=in_cluster |
Linux VM dentro del cluster AHV | Throughput máximo: data plane es virtual-NIC local a DSIP |
3. Backup full — flujo paso a paso
- PTCOMM handshake; recibe JobInfo + Plugin params.
- Cluster discovery: PC v4 con fallback v3, retorna PE IP + JWT 15-min (cookie
NTNX_IGW_SESSION). POST /api/nutanix/v3/vms/{uuid}/snapshot(o v4 equivalente). RAIISnapshotGuardgarantiza delete on drop.- Clone snapshot disks a un Volume Group temporario (Prism API).
- Attach VG al proxy/FD vía iSCSI:
iscsiadm -m discovery+iscsiadm -m node --login. - Enumera
/dev/disk/by-path/...vía sysfs scan; mapea disk ↔ block device por LUN. - Emite FNAME packets:
@nutanix/<cluster>/<vm-uuid>/vm-metadata.json,@nutanix/.../disks/disk-<idx>-<id>.raw. - Stream bytes en reads O_DIRECT 1 MiB / 4 KiB-aligned → D-packets.
- Logout iSCSI, delete VG, delete snapshot (a menos que sea la CBT reference).
- Persiste estado CBT:
reference_recovery_point_ext_id(v4) osnapshot_uuid(v3) en/var/lib/podheitor-nutanix/bitmap/<cluster>/<vm-uuid>.json. - PTCOMM F (end-of-data), wait FD ack, T (terminate).
4. Backup incremental — CRT v4 con fallback v3
El paso 5 del flujo full se convierte en:
- Crea nuevo snapshot (current). Mantiene el reference snapshot anterior.
- Por disco: llama
compute-changed-regions(v4) o/data/changed_regions(v3) con(reference, current). - Pagina: hasta 10.000 regiones por response, sigue
nextOffsethasta agotar. - Emite extents modificados en formato PHCBT01 (magic + original_size + region_count + {offset, length, data} × N) sobre D-packets.
- Hybrid path: dense extents → iSCSI attach + read; sparse extents → REST range-GET. Heurística por densidad.
- En éxito: rotate. Delete old reference, promote current a new reference.
5. RAII guards — limpieza determinística
Snapshot Nutanix huérfano = capacity leak en el cluster. VG huérfano = LUN target zombi. Sesión iSCSI abierta = device file zombi en el FD. El backend lo resuelve vía Rust Drop chain inverso:
| Guard | Recurso | Drop action |
|---|---|---|
SnapshotGuard |
Recovery point Prism | Delete vía API |
VolumeGroupGuard |
VG temporario | Delete vía API |
IscsiSessionGuard |
iSCSI session | iscsiadm -m node --logout |
CleanupGuard |
Catch-all | Atrapa Drop panics; loga errors pero nunca propaga |
Drop ordering es load-bearing: iSCSI logout → VG delete → snapshot delete. El reverse-declaration drop order de Rust da eso gratis, pero insertar guards entre los existentes silenciosamente cambia el orden — la convención está encoded en comment en back_up_vm.
6. Cross-restore inbound — Proxmox/vSphere/Hyper-V → AHV
Detección en el scan de FNAME (primer file del job):
| Prefijo FNAME | Pipeline |
|---|---|
@proxmox/<vmid>/disks/*.raw |
raw → qcow2 (qemu-img convert) → Image Service upload |
@vsphere/<vm>/disks/*.vmdk |
vmdk → qcow2 → Image Service upload |
@hyperv/<vm>/disks/*.vhdx |
vhdx → qcow2 → Image Service upload |
VM config (.conf / .vmx / .vmcx XML) es traducida a AHV vm_spec_v3:
| Source field | AHV target |
|---|---|
| Memory (MB) | resources.memory_size_mib |
| vCPUs | num_sockets × num_vcpus_per_socket |
| Firmware BIOS/UEFI | resources.boot_config.boot_type |
| SCSI/IDE disks | disk_list[].device_properties.device_type=DISK, adapter_type=SCSI |
| NIC MAC+VLAN | nic_list[].mac_address + subnet_reference vía network_map |
7. Replicación vendor-neutral (PHCBT01 over TLS)
A diferencia de las Nutanix Protection Policies, que exigen Nutanix en ambas puntas, la replicación PodHeitor opera sobre PHCBT01-over-TLS en el puerto 9848 — mismo formato de los plugins Proxmox/vSphere/Hyper-V. El receiver puede ser Nutanix, Proxmox, o cualquier host con peer FD PodHeitor.
- Seed: full inicial vía el mismo camino de backup, marcado como reference.
- Bitmap-push: ciclos periódicos leen CRT delta, envían vía TLS al receiver.
- Failover modes: planned, unplanned, test, undo, permanent.
8. Disk-only y alternate-cluster restore
Dos modos ausentes del BEE AHV v18:
- Disk-only restore: restaura solo
disk-N.rawa un device path arbitrario en el FD host (sin upload al Image Service, sin creación de VM). Caso de uso: forense, recuperación de archivo específico vía mount manual. - Alternate-cluster restore: el parámetro
target_clusterredirecciona el restore a PE distinto del origen. Combina conrestore_vm_name=ynetwork_map=para evitar IP collision.
9. Anti-patterns documentados
- No use
prism_insecure=trueen producción. Existe para Nutanix CE (cert self-signed default). Importe la CA del PC en el trust store del FD en vez de bypass. - No invierta el orden de Drop de los guards. Delete de snapshot antes de logout iSCSI deja device files zombis en el FD.
- No corra
proxy_mode=externalsindsip=explícito. El fallback acluster_namefunciona en lab pero es frágil en producción (DNS, multi-DSIP). - No corra replicación contra cluster con Protection Policies activas en la misma VM. Conflicto de snapshots; el flujo actual no detecta automáticamente.
10. License posture
El plugin se distribuye bajo LicenseRef-PodHeitor-Proprietary. El backend es binario Rust standalone — no vincula estáticamente ningún source AGPLv3 de Bacula. El shim C++ es minimalista (~120 LOC, constants-only) y linka contra la Bacula metaplugin framework dynamically.
¿Listo para evaluar?
Trial gratuito de 30 días para clusters Nutanix AHV (Prism Central pc.2024.3+ recomendado, pc.2023.x soportado vía fallback v3). Garantizamos al menos 50% de descuento vs Bacula Enterprise, Veeam o Commvault, con cross-restore y replicación vendor-neutral incluidos.
Heitor Faria — Fundador, PodHeitor International
✉ [email protected]
☎ +1 (789) 726-1749 · +55 (61) 98268-4220 (WhatsApp)
🔗 Página del plugin PodHeitor Nutanix
Disponível em:
Português (Portugués, Brasil)
English (Inglés)
Español