www/proxmox.php
2026-06-27 21:44:44 +00:00

212 lines
8.6 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
require_once __DIR__.'/inc/common.php';
define('PMX_HOST', 'https://192.168.10.150:8006');
define('PMX_USER', 'root@pam');
define('PMX_PASS', 'master2000');
define('PMX_NODE', 'pve');
function pmx_auth(): ?array {
$ch = curl_init(PMX_HOST.'/api2/json/access/ticket');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query(['username' => PMX_USER, 'password' => PMX_PASS]),
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => 6,
]);
$r = json_decode(curl_exec($ch), true);
curl_close($ch);
return $r['data'] ?? null;
}
function pmx_get(string $path, array $auth): ?array {
$ch = curl_init(PMX_HOST.'/api2/json'.$path);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => 6,
CURLOPT_HTTPHEADER => ['Cookie: PVEAuthCookie='.$auth['ticket']],
]);
$r = json_decode(curl_exec($ch), true);
curl_close($ch);
return $r['data'] ?? null;
}
function fmt_bytes(int $b): string {
if ($b >= 1073741824) return round($b/1073741824, 1).' GB';
if ($b >= 1048576) return round($b/1048576, 1).' MB';
return round($b/1024, 1).' KB';
}
function fmt_uptime(int $s): string {
$d = intdiv($s, 86400); $h = intdiv($s % 86400, 3600); $m = intdiv($s % 3600, 60);
return $d ? "{$d}d {$h}h" : ($h ? "{$h}h {$m}m" : "{$m}m");
}
function pct_color(float $p): string {
if ($p >= 85) return '#f85149';
if ($p >= 60) return '#d29922';
return '#3fb950';
}
$auth = pmx_auth();
$error = null;
$node = $containers = $vms = null;
if (!$auth) {
$error = 'Não foi possível autenticar na API do Proxmox.';
} else {
$node = pmx_get('/nodes/'.PMX_NODE.'/status', $auth);
$storage = pmx_get('/nodes/'.PMX_NODE.'/storage', $auth) ?? [];
$containers = pmx_get('/nodes/'.PMX_NODE.'/lxc', $auth) ?? [];
$vms = pmx_get('/nodes/'.PMX_NODE.'/qemu', $auth) ?? [];
usort($containers, fn($a,$b) => $a['vmid'] <=> $b['vmid']);
usort($vms, fn($a,$b) => $a['vmid'] <=> $b['vmid']);
$storage = array_filter($storage, fn($s) => ($s['active'] ?? 0) && ($s['total'] ?? 0) > 0);
usort($storage, fn($a,$b) => strcmp($a['storage'], $b['storage']));
}
$title = 'Proxmox';
ob_start();
?>
<div class="page-header">
<div>
<div class="breadcrumb"><a href="/painel.php">Painel</a><span class="sep"></span>Proxmox</div>
<h1>Proxmox <span style="color:var(--muted);font-weight:400;font-size:16px"><?= PMX_NODE ?></span></h1>
</div>
<button onclick="location.reload()" class="btn btn-secondary">↻ Atualizar</button>
</div>
<?php if ($error): ?>
<div class="alert alert-error">⚠ <?= h($error) ?></div>
<?php else: ?>
<?php if ($node):
$cpu_pct = round(($node['cpu'] ?? 0) * 100, 1);
$ram_used = $node['memory']['used'] ?? 0;
$ram_tot = $node['memory']['total'] ?? 1;
$ram_pct = round($ram_used / $ram_tot * 100, 1);
?>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px;margin-bottom:20px">
<?php foreach ([
['CPU', $cpu_pct.'%', $cpu_pct],
['RAM', fmt_bytes($ram_used).' / '.fmt_bytes($ram_tot), $ram_pct],
['Uptime', fmt_uptime($node['uptime'] ?? 0), -1],
] as [$label, $val, $pct]): ?>
<div class="card">
<div class="card-body" style="padding:16px">
<div style="font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:6px"><?= $label ?></div>
<div style="font-size:18px;font-weight:600;color:<?= $pct >= 0 ? pct_color($pct) : 'var(--text)' ?>"><?= $val ?></div>
<?php if ($pct >= 0): ?>
<div style="margin-top:8px;height:4px;background:var(--surface2);border-radius:2px">
<div style="height:4px;border-radius:2px;background:<?= pct_color($pct) ?>;width:<?= min($pct,100) ?>%"></div>
</div>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
<?php foreach ($storage as $s):
$s_used = $s['used'] ?? 0;
$s_tot = $s['total'] ?? 1;
$s_pct = round($s_used / $s_tot * 100, 1);
?>
<div class="card">
<div class="card-body" style="padding:16px">
<div style="font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:6px"><?= h($s['storage']) ?></div>
<div style="font-size:18px;font-weight:600;color:<?= pct_color($s_pct) ?>"><?= fmt_bytes($s_used) ?></div>
<div style="font-size:11px;color:var(--muted);margin-top:2px">de <?= fmt_bytes($s_tot) ?></div>
<div style="margin-top:8px;height:4px;background:var(--surface2);border-radius:2px">
<div style="height:4px;border-radius:2px;background:<?= pct_color($s_pct) ?>;width:<?= min($s_pct,100) ?>%"></div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<!-- LXC Containers -->
<?php if ($containers): ?>
<div class="card" style="margin-bottom:20px">
<div class="card-header">
<h2>Containers LXC <span style="color:var(--muted);font-weight:400;font-size:13px">(<?= count($containers) ?>)</span></h2>
</div>
<div class="table-wrap">
<table>
<thead><tr><th>ID</th><th>Nome</th><th>Estado</th><th>CPU</th><th>RAM</th><th>Uptime</th></tr></thead>
<tbody>
<?php foreach ($containers as $c):
$running = ($c['status'] === 'running');
$cpu_p = $running ? round(($c['cpu'] ?? 0) * 100, 1) : 0;
$ram_p = $running && ($c['maxmem'] ?? 0) ? round(($c['mem'] ?? 0) / $c['maxmem'] * 100, 1) : 0;
?>
<tr>
<td style="font-family:monospace;font-size:12px;color:var(--muted)"><?= $c['vmid'] ?></td>
<td style="font-weight:500"><?= h($c['name']) ?></td>
<td><?php if($running):?><span class="badge" style="background:#0d2818;color:#3fb950">running</span><?php else:?><span class="badge" style="background:#1e2733;color:var(--muted)"><?= h($c['status']) ?></span><?php endif;?></td>
<td style="font-size:12px">
<?php if($running):?>
<span style="color:<?= pct_color($cpu_p) ?>"><?= $cpu_p ?>%</span>
<?php else: ?><span style="color:var(--muted)">—</span><?php endif;?>
</td>
<td style="font-size:12px">
<?php if($running && ($c['maxmem']??0)):?>
<span style="color:<?= pct_color($ram_p) ?>"><?= fmt_bytes($c['mem']??0) ?></span>
<span style="color:var(--muted)"> / <?= fmt_bytes($c['maxmem']) ?></span>
<?php else: ?><span style="color:var(--muted)">—</span><?php endif;?>
</td>
<td style="color:var(--muted);font-size:12px"><?= $running ? fmt_uptime($c['uptime']??0) : '—' ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
<!-- VMs -->
<?php if ($vms): ?>
<div class="card">
<div class="card-header">
<h2>VMs <span style="color:var(--muted);font-weight:400;font-size:13px">(<?= count($vms) ?>)</span></h2>
</div>
<div class="table-wrap">
<table>
<thead><tr><th>ID</th><th>Nome</th><th>Estado</th><th>CPU</th><th>RAM</th><th>Uptime</th></tr></thead>
<tbody>
<?php foreach ($vms as $v):
$running = ($v['status'] === 'running');
$cpu_p = $running ? round(($v['cpu'] ?? 0) * 100, 1) : 0;
$ram_p = $running && ($v['maxmem'] ?? 0) ? round(($v['mem'] ?? 0) / $v['maxmem'] * 100, 1) : 0;
?>
<tr>
<td style="font-family:monospace;font-size:12px;color:var(--muted)"><?= $v['vmid'] ?></td>
<td style="font-weight:500"><?= h($v['name']) ?></td>
<td><?php if($running):?><span class="badge" style="background:#0d2818;color:#3fb950">running</span><?php else:?><span class="badge" style="background:#1e2733;color:var(--muted)"><?= h($v['status']) ?></span><?php endif;?></td>
<td style="font-size:12px">
<?php if($running):?><span style="color:<?= pct_color($cpu_p) ?>"><?= $cpu_p ?>%</span>
<?php else: ?><span style="color:var(--muted)">—</span><?php endif;?>
</td>
<td style="font-size:12px">
<?php if($running && ($v['maxmem']??0)):?>
<span style="color:<?= pct_color($ram_p) ?>"><?= fmt_bytes($v['mem']??0) ?></span>
<span style="color:var(--muted)"> / <?= fmt_bytes($v['maxmem']) ?></span>
<?php else: ?><span style="color:var(--muted)">—</span><?php endif;?>
</td>
<td style="color:var(--muted);font-size:12px"><?= $running ? fmt_uptime($v['uptime']??0) : '—' ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
<?php $content = ob_get_clean(); require __DIR__.'/inc/layout.php';