> */ public array $nodes = [['node' => 'pve']]; /** @var array */ public array $status = [ 'cpuinfo' => ['cpus' => 16], 'memory' => ['total' => 68719476736], // 64 GiB 'pveversion' => 'pve-manager/8.2.2', ]; /** @var array> */ public array $storage = [ ['storage' => 'local', 'type' => 'dir', 'content' => 'iso,vztmpl,backup', 'total' => 1099511627776], ['storage' => 'local-lvm', 'type' => 'lvmthin', 'content' => 'images,rootdir', 'total' => 1099511627776], // 1 TiB ]; public function forHost(Host $host): static { $this->host = $host; return $this; } public function listNodes(): array { return $this->nodes; } public function nodeStatus(string $node): array { return $this->status; } public function nodeStorage(string $node): array { return $this->storage; } // --- VM lifecycle (deterministic; configurable failure hooks for tests) --- public int $vmidCounter = 100; /** @var array */ public array $clonedVmids = []; /** @var array */ public array $runningVmids = []; /** @var array */ public array $cloudInitCalls = []; /** @var array */ public array $resizeCalls = []; /** @var array */ public array $firewallCalls = []; /** @var array recorded guest commands */ public array $guestCommands = []; /** @var array */ private array $guestScripts = []; public int $guestDefaultExit = 0; public string $guestDefaultOut = ''; public bool $guestAgentUp = true; public ?string $forceTaskStatus = null; // set to 'running' to force a poll public string $taskExitStatus = 'OK'; // set to a non-OK value to fail a task public function nextVmid(): int { return $this->vmidCounter++; } public function cloneVm(string $node, int $templateVmid, int $newVmid, string $name): string { $this->clonedVmids[] = $newVmid; return 'UPID:pve:qmclone:'.$newVmid; } public function setCloudInit(string $node, int $vmid, array $params): void { $this->cloudInitCalls[] = $vmid; } public function resizeDisk(string $node, int $vmid, string $disk, string $size): void { $this->resizeCalls[] = $vmid.':'.$disk.':'.$size; } public function startVm(string $node, int $vmid): string { $this->runningVmids[] = $vmid; return 'UPID:pve:qmstart:'.$vmid; } public function vmStatus(string $node, int $vmid): array { return ['status' => in_array($vmid, $this->runningVmids, true) ? 'running' : 'stopped']; } public function vmExists(string $node, int $vmid): bool { return in_array($vmid, $this->clonedVmids, true) || in_array($vmid, $this->runningVmids, true); } public function guestAgentPing(string $node, int $vmid): bool { return $this->guestAgentUp; } public function guestScript(string $substring, int $exitcode, string $out = ''): static { $this->guestScripts[$substring] = ['exitcode' => $exitcode, 'out-data' => $out]; return $this; } public function guestExec(string $node, int $vmid, string $command): array { $this->guestCommands[] = $command; foreach ($this->guestScripts as $substring => $result) { if (str_contains($command, $substring)) { return $result; } } return ['exitcode' => $this->guestDefaultExit, 'out-data' => $this->guestDefaultOut]; } public function guestRan(string $substring): bool { foreach ($this->guestCommands as $command) { if (str_contains($command, $substring)) { return true; } } return false; } public function taskStatus(string $node, string $upid): array { return ['status' => $this->forceTaskStatus ?? 'stopped', 'exitstatus' => $this->taskExitStatus]; } public function applyFirewall(string $node, int $vmid, array $rules): void { $this->firewallCalls[] = (string) $vmid; } }