VDI.pool_migrate (storage live * migration); halted (or no VM) -> VDI.copy, the VBDs made again on the copy, the original destroyed. The SRs offered: attached, * not ISO, not its own, with room for it. Closes with ['moveDisk' => [vdi, sr]]. * * @property Label $heading * @property Label $where * @property ListBox $sr * @property Label $how * @property Label $error * @property Button $move * @property Button $cancel */ final class MoveDiskForm extends Form { public function __construct(private \App\Model\Session $session) { parent::__construct(); } /** XAPI's answers, events and the console go on while this dialog is open. */ protected function tick(float $dt): void { $this->session->tick($dt); } private array $params = []; /** @return array */ public static function paramsFor(Connection $c, string $vdi): array { $cache = $c->cache; $r = $cache->get($vdi) ?? []; $size = (float)($r['virtual_size'] ?? 0); $vm = Actions::vmOfDisk($c, $vdi); $srs = []; foreach ($cache->srs() as $ref => $sr) { $free = (float)$sr['physical_size'] - (float)$sr['physical_utilisation']; if ($ref === ($r['SR'] ?? '') || ($sr['content_type'] ?? '') === 'iso' || !Menus::managed($cache, $ref) || Menus::attached($cache, $ref) === 0 || $free < $size) { continue; } $srs[] = ['ref' => $ref, 'name' => $cache->name($ref) . ' (' . Units::bytes($free) . ' free)']; } $state = $vm === null ? '' : (string)$cache->field($vm, 'power_state', ''); return ['vdi' => $vdi, 'name' => (string)($r['name_label'] ?? ''), 'size' => $size, 'from' => $cache->name((string)($r['SR'] ?? '')), 'srs' => $srs, 'vm' => $vm === null ? '' : $cache->name($vm), 'state' => $state, 'live' => Actions::isLive($c, $vdi)]; } protected function loaded(array $params = []): void { $this->params = $params; $this->heading->text = "Move '" . ($params['name'] ?? '') . "'"; $this->where->text = Units::bytes((float)($params['size'] ?? 0)) . " on '" . ($params['from'] ?? '') . "'" . (($params['vm'] ?? '') !== '' ? " ยท VM '{$params['vm']}'" : ''); $this->sr->items = array_column($params['srs'] ?? [], 'name'); $this->sr->selected = ($params['srs'] ?? []) === [] ? -1 : 0; $this->how->text = !empty($params['live']) ? 'The VM is running: the disk moves while it works (storage live migration).' : 'The disk is copied to the new storage repository, the VM is given the copy, then the original is deleted.'; $this->error->text = ($params['srs'] ?? []) === [] ? 'No other storage repository has room for this disk.' : ''; if (in_array($params['state'] ?? '', ['Suspended', 'Paused'], true)) { $this->error->text = 'The VM is ' . strtolower((string)$params['state']) . ': start it or shut it down first.'; } $this->move->enabled = $this->error->text === ''; } public function onMoveClick(mixed $sender = null): void { $sr = $this->params['srs'][(int)$this->sr->selected] ?? null; if ($sr === null || !$this->move->enabled) { $this->error->text = $this->error->text ?: 'Choose a storage repository.'; return; } $this->close(['moveDisk' => ['vdi' => $this->params['vdi'] ?? '', 'sr' => $sr['ref']]]); } public function onCancelClick(Button $sender): void { $this->close(); } }