- Added main application entry point (app.jsx) and bootstrap file for React setup. - Created Wiki index page (Index.jsx) for documentation and file management. - Implemented utility functions for formatting and status handling in utils.js. - Set up Blade template (app.blade.php) for Inertia.js integration. - Defined API routes for metrics and terminal access in api.php. - Established console commands for scheduled tasks in console.php. - Created web routes for various application features including authentication, hypervisors, containers, cloud accounts, security, backups, and wiki management in web.php. - Developed setup scripts for Windows (setup.ps1) and Linux (setup.sh) environments. - Configured Tailwind CSS for styling with custom themes and animations in tailwind.config.js. - Set up Vite for asset bundling and development server in vite.config.js.
180 lines
6.0 KiB
PHP
180 lines
6.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Hypervisor;
|
|
|
|
use App\Models\Hypervisor;
|
|
use App\Models\VirtualMachine;
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\RequestOptions;
|
|
|
|
class ProxmoxDriver implements HypervisorDriverInterface
|
|
{
|
|
private Client $client;
|
|
private string $ticket = '';
|
|
private string $csrfToken = '';
|
|
|
|
public function __construct(private Hypervisor $hypervisor)
|
|
{
|
|
$this->client = new Client([
|
|
'base_uri' => "https://{$hypervisor->host}:{$hypervisor->port}/api2/json/",
|
|
'timeout' => 30,
|
|
RequestOptions::VERIFY => $hypervisor->ssl_verify,
|
|
]);
|
|
}
|
|
|
|
private function authenticate(): void
|
|
{
|
|
if ($this->ticket) return;
|
|
|
|
$response = $this->client->post('access/ticket', [
|
|
'form_params' => [
|
|
'username' => $this->hypervisor->username,
|
|
'password' => $this->hypervisor->password,
|
|
],
|
|
]);
|
|
|
|
$data = json_decode($response->getBody()->getContents(), true)['data'];
|
|
$this->ticket = $data['ticket'];
|
|
$this->csrfToken = $data['CSRFPreventionToken'];
|
|
}
|
|
|
|
private function authHeaders(): array
|
|
{
|
|
return [
|
|
'Cookie' => "PVEAuthCookie={$this->ticket}",
|
|
'CSRFPreventionToken' => $this->csrfToken,
|
|
];
|
|
}
|
|
|
|
public function testConnection(): array
|
|
{
|
|
$this->authenticate();
|
|
$response = $this->client->get('version', ['headers' => $this->authHeaders()]);
|
|
return json_decode($response->getBody()->getContents(), true)['data'] ?? [];
|
|
}
|
|
|
|
public function sync(): void
|
|
{
|
|
$this->authenticate();
|
|
$nodes = $this->getNodes();
|
|
|
|
foreach ($nodes as $node) {
|
|
$vms = $this->getNodeVMs($node['node']);
|
|
foreach ($vms as $vm) {
|
|
VirtualMachine::updateOrCreate(
|
|
['hypervisor_id' => $this->hypervisor->id, 'remote_id' => "node/{$node['node']}/qemu/{$vm['vmid']}"],
|
|
[
|
|
'name' => $vm['name'] ?? "VM-{$vm['vmid']}",
|
|
'status' => $vm['status'],
|
|
'cpu_count' => $vm['cpus'] ?? 0,
|
|
'memory_mb' => isset($vm['mem']) ? intval($vm['mem'] / 1048576) : 0,
|
|
'cpu_usage' => ($vm['cpu'] ?? 0) * 100,
|
|
'memory_usage' => isset($vm['mem'], $vm['maxmem']) && $vm['maxmem'] > 0
|
|
? ($vm['mem'] / $vm['maxmem']) * 100 : 0,
|
|
'host_node' => $node['node'],
|
|
'metadata' => $vm,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
$this->hypervisor->update(['status' => 'online', 'last_sync_at' => now(), 'last_error' => null]);
|
|
}
|
|
|
|
private function getNodes(): array
|
|
{
|
|
$response = $this->client->get('nodes', ['headers' => $this->authHeaders()]);
|
|
return json_decode($response->getBody()->getContents(), true)['data'] ?? [];
|
|
}
|
|
|
|
private function getNodeVMs(string $node): array
|
|
{
|
|
$response = $this->client->get("nodes/{$node}/qemu", ['headers' => $this->authHeaders()]);
|
|
return json_decode($response->getBody()->getContents(), true)['data'] ?? [];
|
|
}
|
|
|
|
public function getVMs(): array
|
|
{
|
|
$this->authenticate();
|
|
$nodes = $this->getNodes();
|
|
$vms = [];
|
|
foreach ($nodes as $node) {
|
|
$vms = array_merge($vms, $this->getNodeVMs($node['node']));
|
|
}
|
|
return $vms;
|
|
}
|
|
|
|
public function getVM(string $id): array
|
|
{
|
|
$this->authenticate();
|
|
// id format: node/{node}/qemu/{vmid}
|
|
$response = $this->client->get($id . '/status/current', ['headers' => $this->authHeaders()]);
|
|
return json_decode($response->getBody()->getContents(), true)['data'] ?? [];
|
|
}
|
|
|
|
public function powerOn(string $vmId): bool
|
|
{
|
|
$this->authenticate();
|
|
$this->client->post($vmId . '/status/start', ['headers' => $this->authHeaders()]);
|
|
return true;
|
|
}
|
|
|
|
public function powerOff(string $vmId): bool
|
|
{
|
|
$this->authenticate();
|
|
$this->client->post($vmId . '/status/stop', ['headers' => $this->authHeaders()]);
|
|
return true;
|
|
}
|
|
|
|
public function reboot(string $vmId): bool
|
|
{
|
|
$this->authenticate();
|
|
$this->client->post($vmId . '/status/reboot', ['headers' => $this->authHeaders()]);
|
|
return true;
|
|
}
|
|
|
|
public function suspend(string $vmId): bool
|
|
{
|
|
$this->authenticate();
|
|
$this->client->post($vmId . '/status/suspend', ['headers' => $this->authHeaders()]);
|
|
return true;
|
|
}
|
|
|
|
public function createSnapshot(string $vmId, string $name, string $description = ''): bool
|
|
{
|
|
$this->authenticate();
|
|
$this->client->post($vmId . '/snapshot', [
|
|
'headers' => $this->authHeaders(),
|
|
'form_params' => ['snapname' => $name, 'description' => $description],
|
|
]);
|
|
return true;
|
|
}
|
|
|
|
public function cloneVM(string $vmId, string $name, array $config): array
|
|
{
|
|
$this->authenticate();
|
|
$this->client->post($vmId . '/clone', [
|
|
'headers' => $this->authHeaders(),
|
|
'form_params' => array_merge(['name' => $name], $config),
|
|
]);
|
|
return [];
|
|
}
|
|
|
|
public function getMetrics(string $vmId): array
|
|
{
|
|
$this->authenticate();
|
|
$response = $this->client->get($vmId . '/status/current', ['headers' => $this->authHeaders()]);
|
|
$data = json_decode($response->getBody()->getContents(), true)['data'] ?? [];
|
|
return [
|
|
'cpu_usage' => ($data['cpu'] ?? 0) * 100,
|
|
'memory_usage' => isset($data['mem'], $data['maxmem']) && $data['maxmem'] > 0
|
|
? ($data['mem'] / $data['maxmem']) * 100 : 0,
|
|
];
|
|
}
|
|
|
|
public function deployTemplate(array $templateConfig, array $deployConfig): array
|
|
{
|
|
return $this->cloneVM($templateConfig['remote_id'], $deployConfig['name'], $deployConfig);
|
|
}
|
|
}
|