[vm, name, description, size (bytes, a float), sr]] * or ['attachDisk' => [vm, vdi]]. * * @property Label $heading * @property Label $where * @property Container $addPanel * @property TextBox $name * @property TextBox $description * @property TextBox $size * @property ComboBox $sr * @property Container $attachPanel * @property ListBox $disk * @property Label $note * @property Label $error * @property Button $ok * @property Button $cancel */ final class DiskForm 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 $vm, string $mode): array { $cache = $c->cache; $default = (string)$cache->field((string)$cache->poolRef(), 'default_SR', ''); $srs = []; $free = []; foreach ($cache->srs() as $ref => $sr) { if (($sr['content_type'] ?? '') === 'iso' || !Menus::managed($cache, $ref) || Menus::attached($cache, $ref) === 0) { continue; } $srs[] = ['ref' => $ref, 'name' => $cache->name($ref) . ' (' . Units::bytes((float)$sr['physical_size'] - (float)$sr['physical_utilisation']) . ' free)']; foreach ((array)$sr['VDIs'] as $vdi) { $d = $cache->get((string)$vdi); if ($d !== null && (array)$d['VBDs'] === [] && empty($d['is_a_snapshot']) && empty($d['read_only'])) { $free[] = ['ref' => (string)$vdi, 'name' => $d['name_label'] . ' (' . Units::bytes((float)$d['virtual_size']) . ', ' . $cache->name($ref) . ')']; } } } usort($srs, fn ($a, $b) => ($b['ref'] === $default) <=> ($a['ref'] === $default)); $disks = count($cache->disksOf($vm)); return ['vm' => $vm, 'vmName' => $cache->name($vm), 'mode' => $mode, 'srs' => $srs, 'free' => $free, 'running' => $cache->field($vm, 'power_state') === 'Running', 'name' => $cache->name($vm) . ' ' . $disks]; } protected function loaded(array $params = []): void { $this->params = $params; $add = ($params['mode'] ?? 'add') === 'add'; $this->heading->text = $add ? 'Add Virtual Disk' : 'Attach Virtual Disk'; $this->where->text = "To VM '" . ($params['vmName'] ?? '') . "'"; $this->addPanel->visible = $add; $this->attachPanel->visible = !$add; $this->ok->text = $add ? 'Add' : 'Attach'; $this->name->text = (string)($params['name'] ?? 'disk'); $this->description->text = ''; $this->size->text = '20'; $this->sr->items = array_column($params['srs'] ?? [], 'name'); $this->sr->selected = ($params['srs'] ?? []) === [] ? -1 : 0; $this->disk->items = array_column($params['free'] ?? [], 'name'); $this->disk->selected = ($params['free'] ?? []) === [] ? -1 : 0; $this->note->text = !empty($params['running']) ? 'The VM is running: the disk is plugged in at once.' : ''; $this->error->text = !$add && ($params['free'] ?? []) === [] ? 'Every disk of the pool is in use.' : ''; if ($add) { $this->setFocus($this->name); } } public function onOkClick(mixed $sender = null): void { $vm = (string)($this->params['vm'] ?? ''); if (($this->params['mode'] ?? 'add') !== 'add') { $disk = $this->params['free'][(int)$this->disk->selected] ?? null; if ($disk === null) { $this->error->text = 'Choose a disk.'; return; } $this->close(['attachDisk' => ['vm' => $vm, 'vdi' => $disk['ref']]]); return; } $size = (float)str_replace(',', '.', trim($this->size->text)); $sr = $this->params['srs'][(int)$this->sr->selected] ?? null; if (trim($this->name->text) === '') { $this->error->text = 'Enter a name for the disk.'; return; } if ($size < 0.01 || $size > 65536) { $this->error->text = 'The size is a number of GB, from 0.01 to 65536.'; return; } if ($sr === null) { $this->error->text = 'There is no storage repository to put the disk on.'; return; } // bytes stay a float: 2 GB and more do not fit the browser's 32-bit integers $this->close(['addDisk' => ['vm' => $vm, 'name' => trim($this->name->text), 'description' => $this->description->text, 'size' => floor($size * 1073741824.0), 'sr' => $sr['ref']]]); } public function onCancelClick(Button $sender): void { $this->close(); } }