*/ public static function standalone(Session $session, ?Connection $except = null): array { return array_values(array_filter($session->connections, fn (Connection $c) => $c !== $except && $c->isConnected() && !$c->cache->isRealPool())); } /** Why a server cannot join a pool ('' = it can): XAPI refuses a host with running or suspended VMs. */ public static function cannotJoin(Connection $c): string { foreach ($c->cache->vms() as $vm) { if (in_array($vm['power_state'], ['Running', 'Paused', 'Suspended'], true)) { return 'it has running or suspended VMs'; } } return ''; } /** @return list|string> the Pool menu of the menu bar */ public static function poolMenu(?Connection $c, string $ref, string $kind): array { $session = Session::$current; $standalone = $session === null ? [] : self::standalone($session); $pool = $kind === 'pool' && $c !== null; // a pool selected: its own menu (Add Server…, Connection Addresses… are in it) return [Commands::item('pool.new', 'New Pool…', $standalone !== [], 'new-pool'), '-', ...($pool ? Commands::context($c, $ref, 'pool') : [Commands::item('pool.addServer', 'Add Server…', false, 'add-server'), Commands::item('pool.addresses', 'Connection Addresses…', $c !== null && $c->isConnected() && $kind === 'host')])]; } /** @return list|string> under XenCenter (the root's right click) */ public static function rootItems(): array { $session = Session::$current; return ['-', Commands::item('pool.new', 'New Pool…', $session !== null && self::standalone($session) !== [], 'new-pool')]; } /** @return list|string> the pool's right click */ public static function poolItems(?Connection $c): array { $session = Session::$current; return [Commands::item('pool.addServer', 'Add Server…', $c !== null && $session !== null && self::standalone($session, $c) !== [], 'add-server'), Commands::item('pool.addresses', 'Connection Addresses…'), '-']; } /** @return list|string> a server's: in a pool, leave it / lead it; alone, join one of the connected pools */ public static function hostItems(?Connection $c, string $host): array { if ($c === null || !$c->isConnected()) { return []; } $items = ['-']; $master = (string)$c->cache->master(); if (count($c->cache->hosts()) > 1) { $idle = $c->cache->vmsOn($host) === []; $items[] = Commands::item('host.designateMaster', 'Make this server the pool master', $host !== $master); $items[] = Commands::item('host.removeFromPool', 'Remove Server from Pool', $host !== $master && $idle); } else { $reason = self::cannotJoin($c); foreach (Session::$current === null ? [] : Session::$current->connections as $i => $pool) { if ($pool !== $c && $pool->isConnected() && $pool->cache->isRealPool()) { $items[] = Commands::item('pool.joinTo:' . $i, "Add to Pool '" . $pool->name() . "'", $reason === '', 'pool'); } } } $items[] = Commands::item('pool.addresses', 'Connection Addresses…'); return $items; } /** The questions XenCenter asks first. */ public static function confirmation(string $command, string $name, ?Cache $cache = null): ?string { return match ($command) { 'host.removeFromPool' => "Remove server '$name' from its pool?\n\nIts local storage is destroyed with every virtual disk on it, the VMs stored there are deleted, " . "and the server reboots as a standalone server with an empty configuration. This cannot be undone.\n\nShared storage, and the VMs on it, stay in the pool.", 'host.designateMaster' => "Make server '$name' the new pool master?\n\nThe pool's management moves to it; XenCenter's connection is cut for a moment while the toolstacks restart.", default => null, }; } }