Migration¶
Migration moves a cloud instance between hypervisors, moves managed disks off a storage backend, and drains a node. One rule governs it: the source stays authoritative until a commit, and nothing is released or destroyed early.
Scope honesty
The panel-side orchestration, preflight, compatibility rules, reservations, networking plans, recovery state machine, token issuance and semantic agent tasks are implemented and mock-tested. Real live migration, real disk transfer and real route moves are NOT TESTED on physical hardware in this deliverable. The panel only emits semantic tasks, never raw libvirt URIs, host paths or command strings.

Lifecycle¶
REQUESTED → READY → PREPARING_TARGET → TRANSFERRING → VERIFYING_DISK
→ PREPARING_NETWORK → STOPPING_SOURCE → DEFINING_TARGET
→ (LIVE_MIGRATING) → STARTING_TARGET → VERIFYING_TARGET
→ COMMITTING → COMPLETED → CLEANING_UP
Failures before the point of no return roll back (ROLLING_BACK →
ROLLED_BACK). Failures at or after it surface as RECOVERY_REQUIRED; the
panel never blindly restarts the source.
A renewable exclusive lease blocks a second migration for the same instance
(INSTANCE_MIGRATING). The source hypervisor is retained for a policy window
before cleanup.
Modes¶
| Mode | Behaviour |
|---|---|
LIVE_REQUIRED |
Fails preflight if the target does not advertise live_migration. Never downgrades to cold. |
LIVE_IF_POSSIBLE |
Uses live when supported, otherwise a warning and a cold move. |
AUTO |
Live when possible and policy allows, otherwise cold. |
COLD |
Never live. |
Host-bound resources (CPU host-passthrough, GPU/PCI passthrough, strict NUMA/hugepage requirements) are hard blockers. A same-IP cross-node move is not atomic: a brief network interruption is recorded.
Operator commands¶
# Read-only: blockers, warnings, strategies, candidates. ZERO mutations.
php artisan pterocloud:migration:preflight <instance_uuid> --target=<hv_uuid> --mode=AUTO --json
# Request + start (interactive confirmation; --force is explicit and warned).
php artisan pterocloud:migration:start <instance_uuid> --target=<hv_uuid> --mode=COLD
php artisan pterocloud:migration:status <migration_uuid> --json
php artisan pterocloud:migration:recover <migration_uuid> [--mark] # read-only unless --mark
php artisan pterocloud:migration:health --json
--dry-run paths call the real preflight/compatibility/reporting logic and
perform zero mutations.
Admin API¶
All endpoints are admin-only. The serializers expose normalized source/target details but never a secret, a provider task id (UPID / libvirt URI / VMID) or a transfer token.
POST /admin/pterocloud/instances/{uuid}/migrations/preflight
POST /admin/pterocloud/instances/{uuid}/migrations
GET /admin/pterocloud/migrations/{uuid}
POST /admin/pterocloud/migrations/{uuid}/cancel
POST /admin/pterocloud/migrations/{uuid}/rollback
Admin pages: /admin/pterocloud/migrations,
/admin/pterocloud/migrations/{uuid}/view,
/admin/pterocloud/instances/view/{uuid}/migrate/wizard.
What is proven vs not¶
Mock-proven: every preflight blocker code, warnings separated from blockers, dry-run non-mutation, compatibility rules, storage strategies, IP portability, MAC collision, firewall/port-forward plans, reservations and races, rollback vs point of no return, reconciliation, token scope/expiry/replay, evacuation drain-first/partial, admin endpoints and pages, command dry-runs, and a 1000-VM plan that stays responsive.
NOT TESTED on hardware: actual QEMU/libvirt live migration, actual disk copy
throughput, actual route/BGP move, actual VFIO/GPU movement, Proxmox move_disk
against a real cluster, and agent-side execution.
Related¶
- High availability
- Troubleshooting: migration
PC-MIG-###in the error reference