Release v1.0.2: Hotfix, Live Diagramme VMs und PVE Nodex
This commit is contained in:
+147
-20
@@ -3,16 +3,64 @@
|
||||
if (!defined('PDO::ATTR_DRIVER_NAME')) exit; // Schutz vor direktem Aufruf
|
||||
|
||||
if ($action === 'get_stats') {
|
||||
$stmt = $pdo->query("SELECT * FROM nodes WHERE type = 'pve'"); $nodes = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$data = ['cpu_cores' => 0, 'cpu_used' => 0, 'ram_total' => 0, 'ram_used' => 0, 'disk_total' => 0, 'disk_used' => 0, 'cpu_percent' => 0];
|
||||
$stmt = $pdo->query("SELECT * FROM nodes WHERE type = 'pve'");
|
||||
$nodes = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$data = [
|
||||
'cpu_cores' => 0, 'cpu_used' => 0, 'ram_total' => 0, 'ram_used' => 0,
|
||||
'disk_total' => 0, 'disk_used' => 0, 'cpu_percent' => 0, 'nodes_net' => [],
|
||||
'cluster_stats' => ['nodes_total' => count($nodes), 'nodes_online' => 0, 'vms_total' => 0, 'vms_running' => 0, 'vms_stopped' => 0]
|
||||
];
|
||||
|
||||
$seenNodes = [];
|
||||
$seenVms = [];
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
$nData = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/nodes");
|
||||
if (isset($nData['data'])) {
|
||||
foreach ($nData['data'] as $nInfo) {
|
||||
if ($nInfo['status'] === 'online') {
|
||||
$data['cpu_cores'] += $nInfo['maxcpu'] ?? 0; $data['cpu_used'] += ($nInfo['cpu'] ?? 0) * ($nInfo['maxcpu'] ?? 0);
|
||||
$data['ram_total'] += $nInfo['maxmem'] ?? 0; $data['ram_used'] += $nInfo['mem'] ?? 0;
|
||||
$data['disk_total'] += $nInfo['maxdisk'] ?? 0; $data['disk_used'] += $nInfo['disk'] ?? 0;
|
||||
// Duplikate (z.B. in Clustern) vermeiden
|
||||
if (!isset($seenNodes[$nInfo['node']])) {
|
||||
$seenNodes[$nInfo['node']] = true;
|
||||
|
||||
if ($nInfo['status'] === 'online') {
|
||||
$data['cluster_stats']['nodes_online']++;
|
||||
$data['cpu_cores'] += $nInfo['maxcpu'] ?? 0;
|
||||
$data['cpu_used'] += ($nInfo['cpu'] ?? 0) * ($nInfo['maxcpu'] ?? 0);
|
||||
$data['ram_total'] += $nInfo['maxmem'] ?? 0;
|
||||
$data['ram_used'] += $nInfo['mem'] ?? 0;
|
||||
$data['disk_total'] += $nInfo['maxdisk'] ?? 0;
|
||||
$data['disk_used'] += $nInfo['disk'] ?? 0;
|
||||
|
||||
$nRrd = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/nodes/{$nInfo['node']}/rrddata?timeframe=hour&cf=AVERAGE");
|
||||
$netin = 0; $netout = 0;
|
||||
if (isset($nRrd['data']) && is_array($nRrd['data'])) {
|
||||
for ($i = count($nRrd['data']) - 1; $i >= 0; $i--) {
|
||||
if (isset($nRrd['data'][$i]['netin']) && $nRrd['data'][$i]['netin'] !== null) {
|
||||
$netin = $nRrd['data'][$i]['netin'];
|
||||
$netout = $nRrd['data'][$i]['netout'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$data['nodes_net'][] = ['name' => $nInfo['node'], 'netin' => $netin, 'netout' => $netout];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VMs von allen angebundenen Hosts ziehen und Duplikate filtern
|
||||
$vms = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/cluster/resources?type=vm");
|
||||
if (isset($vms['data'])) {
|
||||
foreach($vms['data'] as $vm) {
|
||||
$uniqueId = $vm['vmid'] . '@' . ($vm['node'] ?? 'unknown');
|
||||
if (!isset($seenVms[$uniqueId])) {
|
||||
$seenVms[$uniqueId] = true;
|
||||
$data['cluster_stats']['vms_total']++;
|
||||
if (isset($vm['status']) && $vm['status'] === 'running') {
|
||||
$data['cluster_stats']['vms_running']++;
|
||||
} else {
|
||||
$data['cluster_stats']['vms_stopped']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,12 +70,14 @@ if ($action === 'get_stats') {
|
||||
}
|
||||
|
||||
if ($action === 'get_top_vms') {
|
||||
$stmt = $pdo->query("SELECT * FROM nodes WHERE type = 'pve'"); $nodes = $stmt->fetchAll(PDO::FETCH_ASSOC); $allVms = [];
|
||||
$stmt = $pdo->query("SELECT * FROM nodes WHERE type = 'pve'"); $nodes = $stmt->fetchAll(PDO::FETCH_ASSOC); $allVms = []; $seenVms = [];
|
||||
foreach ($nodes as $node) {
|
||||
$vms = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/cluster/resources?type=vm");
|
||||
if (isset($vms['data'])) {
|
||||
foreach ($vms['data'] as $vm) {
|
||||
if (checkVmPermission($pdo, $vm['vmid'])) {
|
||||
$uniqueId = $vm['vmid'] . '@' . ($vm['node'] ?? 'unknown');
|
||||
if (!isset($seenVms[$uniqueId]) && checkVmPermission($pdo, $vm['vmid'])) {
|
||||
$seenVms[$uniqueId] = true;
|
||||
$vm['node_id'] = $node['id'];
|
||||
$vm['node_ip'] = $node['ip_address'];
|
||||
$vm['host'] = $vm['node'] ?? 'unknown';
|
||||
@@ -41,12 +91,14 @@ if ($action === 'get_top_vms') {
|
||||
}
|
||||
|
||||
if ($action === 'get_all_vms') {
|
||||
$stmt = $pdo->query("SELECT * FROM nodes WHERE type = 'pve'"); $nodes = $stmt->fetchAll(PDO::FETCH_ASSOC); $allVms = [];
|
||||
$stmt = $pdo->query("SELECT * FROM nodes WHERE type = 'pve'"); $nodes = $stmt->fetchAll(PDO::FETCH_ASSOC); $allVms = []; $seenVms = [];
|
||||
foreach ($nodes as $node) {
|
||||
$vms = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/cluster/resources?type=vm");
|
||||
if (isset($vms['data'])) {
|
||||
foreach ($vms['data'] as $vm) {
|
||||
if (checkVmPermission($pdo, $vm['vmid'])) {
|
||||
$uniqueId = $vm['vmid'] . '@' . ($vm['node'] ?? 'unknown');
|
||||
if (!isset($seenVms[$uniqueId]) && checkVmPermission($pdo, $vm['vmid'])) {
|
||||
$seenVms[$uniqueId] = true;
|
||||
$vm['node_id'] = $node['id'];
|
||||
$vm['node_ip'] = $node['ip_address'];
|
||||
$vm['host'] = $vm['node'] ?? 'unknown';
|
||||
@@ -68,14 +120,63 @@ if ($action === 'vm_action') {
|
||||
}
|
||||
|
||||
if ($action === 'get_nodes') { if (!$isAdmin) exit; $stmt = $pdo->query("SELECT id, name, ip_address, type FROM nodes"); echo json_encode(['success' => true, 'data' => $stmt->fetchAll(PDO::FETCH_ASSOC)]); exit; }
|
||||
|
||||
if ($action === 'delete_node') { if (!$isAdmin) exit; $stmt = $pdo->prepare("DELETE FROM nodes WHERE id = ?"); $stmt->execute([$_POST['id']]); logAudit('Server gelöscht', "Node ID: {$_POST['id']}"); echo json_encode(['success' => true]); exit; }
|
||||
|
||||
if ($action === 'add_node') {
|
||||
if (!$isAdmin) exit;
|
||||
|
||||
$name = trim($_POST['name']);
|
||||
$ip = trim($_POST['ip']);
|
||||
$user = trim($_POST['user']);
|
||||
$pass = trim($_POST['pass']);
|
||||
$type = $_POST['type'] ?? 'pve';
|
||||
|
||||
$tokenIdToSave = $user;
|
||||
$tokenSecretToSave = $pass;
|
||||
|
||||
if ($type === 'pve') {
|
||||
$chAuth = curl_init("https://{$ip}:8006/api2/json/access/ticket");
|
||||
curl_setopt_array($chAuth, [
|
||||
CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_SSL_VERIFYHOST => false, CURLOPT_TIMEOUT => 5,
|
||||
CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query(['username' => $user, 'password' => $pass])
|
||||
]);
|
||||
$authRes = json_decode(curl_exec($chAuth), true);
|
||||
curl_close($chAuth);
|
||||
|
||||
if(!isset($authRes['data']['ticket'])) {
|
||||
echo json_encode(['success' => false, 'error' => 'Proxmox Login fehlgeschlagen. Passwort falsch?']); exit;
|
||||
}
|
||||
|
||||
$ticket = $authRes['data']['ticket'];
|
||||
$csrf = $authRes['data']['CSRFPreventionToken'];
|
||||
|
||||
$tokenName = 'pvedash' . rand(1000, 9999);
|
||||
$chToken = curl_init("https://{$ip}:8006/api2/json/access/users/{$user}/token/{$tokenName}");
|
||||
curl_setopt_array($chToken, [
|
||||
CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_SSL_VERIFYHOST => false, CURLOPT_TIMEOUT => 5,
|
||||
CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query(['privsep' => 0]),
|
||||
CURLOPT_HTTPHEADER => ["Cookie: PVEAuthCookie={$ticket}", "CSRFPreventionToken: {$csrf}"]
|
||||
]);
|
||||
$tokenRes = json_decode(curl_exec($chToken), true);
|
||||
curl_close($chToken);
|
||||
|
||||
if(!isset($tokenRes['data']['value'])) {
|
||||
echo json_encode(['success' => false, 'error' => 'Konnte API Token nicht erstellen. Admin-Rechte?']); exit;
|
||||
}
|
||||
|
||||
$tokenIdToSave = $user . '!' . $tokenName;
|
||||
$tokenSecretToSave = $tokenRes['data']['value'];
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO nodes (name, ip_address, token_id, token_secret, type) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$_POST['name'], $_POST['ip'], $_POST['user'], $_POST['pass'], $_POST['type'] ?? 'pve']);
|
||||
logAudit('Server hinzugefügt', "Node: {$_POST['name']} ({$_POST['ip']})");
|
||||
$stmt->execute([$name, $ip, $tokenIdToSave, $tokenSecretToSave, $type]);
|
||||
logAudit('Server hinzugefügt', "Node: {$name} ({$ip})");
|
||||
echo json_encode(['success' => true]); exit;
|
||||
}
|
||||
|
||||
if ($action === 'get_users') { if (!$isAdmin) exit; $stmt = $pdo->query("SELECT id, username, role FROM users"); echo json_encode(['success' => true, 'data' => $stmt->fetchAll(PDO::FETCH_ASSOC)]); exit; }
|
||||
if ($action === 'delete_user') { if (!$isAdmin) exit; $stmt = $pdo->prepare("DELETE FROM users WHERE id = ?"); $stmt->execute([$_POST['id']]); logAudit('User gelöscht', "User ID: {$_POST['id']}"); echo json_encode(['success' => true]); exit; }
|
||||
if ($action === 'create_user') {
|
||||
@@ -88,10 +189,17 @@ if ($action === 'create_user') {
|
||||
|
||||
if ($action === 'get_pve_nodes') {
|
||||
if (!$isAdmin) exit;
|
||||
$stmt = $pdo->query("SELECT * FROM nodes WHERE type = 'pve'"); $resList = [];
|
||||
$stmt = $pdo->query("SELECT * FROM nodes WHERE type = 'pve'"); $resList = []; $seenNodes = [];
|
||||
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $node) {
|
||||
$nData = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/nodes");
|
||||
if(isset($nData['data'])) { foreach($nData['data'] as $n) { if($n['status'] === 'online') { $resList[] = ['node_id' => $node['id'], 'host' => $n['node'], 'display' => $node['name'] . ' -> ' . $n['node']]; } } }
|
||||
if(isset($nData['data'])) {
|
||||
foreach($nData['data'] as $n) {
|
||||
if($n['status'] === 'online' && !isset($seenNodes[$n['node']])) {
|
||||
$seenNodes[$n['node']] = true;
|
||||
$resList[] = ['node_id' => $node['id'], 'host' => $n['node'], 'display' => $node['name'] . ' -> ' . $n['node']];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
echo json_encode(['success' => true, 'data' => $resList]); exit;
|
||||
}
|
||||
@@ -105,7 +213,7 @@ if ($action === 'create_vm') {
|
||||
$params = ['vmid' => $vmid, 'name' => $_POST['name'], 'memory' => $_POST['memory'], 'cores' => $_POST['cores'], 'net0' => 'virtio,bridge=vmbr0'];
|
||||
$res = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/nodes/{$_POST['host']}/qemu", 'pve', 'POST', $params);
|
||||
logAudit('VM Erstellt', "VMID: {$vmid} Name: {$_POST['name']}");
|
||||
echo json_encode(['success' => isset($res['data']), 'vmid' => $vmid, 'error' => isset($res['data']) ? '' : 'Fehler bei der VM Erstellung in Proxmox.']); exit;
|
||||
echo json_encode(['success' => isset($res['data']), 'vmid' => $vmid, 'error' => isset($res['data']) ? '' : 'Fehler bei Erstellung.']); exit;
|
||||
}
|
||||
|
||||
if ($action === 'get_vm_config') {
|
||||
@@ -208,7 +316,7 @@ if ($action === 'restore_backup') {
|
||||
if (!checkVmPermission($pdo, $_POST['vmid'])) exit;
|
||||
$stmt = $pdo->prepare("SELECT * FROM nodes WHERE id = ?"); $stmt->execute([$_POST['node_id']]); $node = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$res = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/nodes/{$_POST['host']}/{$_POST['type']}/{$_POST['vmid']}/status/current");
|
||||
if (isset($res['data']) && $res['data']['status'] === 'running') { echo json_encode(['success' => false, 'error' => 'VM muss gestoppt sein!']); exit; }
|
||||
if (isset($res['data']) && $res['data']['status'] === 'running') { echo json_encode(['success' => false, 'error' => 'VM gestoppt?']); exit; }
|
||||
$resRestore = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/nodes/{$_POST['host']}/{$_POST['type']}", 'pve', 'POST', ['vmid' => $_POST['vmid'], 'archive' => $_POST['archive'], 'force' => 1]);
|
||||
logAudit('Backup Restore', "VMID: {$_POST['vmid']} Archive: {$_POST['archive']}");
|
||||
echo json_encode(['success' => isset($resRestore['data']), 'error' => 'API Fehler']); exit;
|
||||
@@ -220,12 +328,31 @@ if ($action === 'get_node_status' || $action === 'get_vm_status') {
|
||||
if ($action === 'get_node_status') {
|
||||
$nData = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/nodes");
|
||||
$internalName = $nData['data'][0]['node'] ?? 'pve';
|
||||
$endpoint = "/api2/json/nodes/{$internalName}/status";
|
||||
|
||||
$res = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/nodes/{$internalName}/status");
|
||||
$rrd = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], "/api2/json/nodes/{$internalName}/rrddata?timeframe=hour&cf=AVERAGE");
|
||||
|
||||
$netin = 0; $netout = 0;
|
||||
if (isset($rrd['data']) && is_array($rrd['data'])) {
|
||||
for ($i = count($rrd['data']) - 1; $i >= 0; $i--) {
|
||||
if (isset($rrd['data'][$i]['netin']) && $rrd['data'][$i]['netin'] !== null) {
|
||||
$netin = $rrd['data'][$i]['netin'];
|
||||
$netout = $rrd['data'][$i]['netout'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data = $res['data'] ?? [];
|
||||
$data['netin'] = $netin;
|
||||
$data['netout'] = $netout;
|
||||
$data['is_rrd_net'] = true;
|
||||
|
||||
echo json_encode(['success' => true, 'data' => $data]); exit;
|
||||
} else {
|
||||
$endpoint = "/api2/json/nodes/{$_GET['host']}/{$_GET['type']}/{$_GET['vmid']}/status/current";
|
||||
$res = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], $endpoint);
|
||||
echo json_encode(['success' => true, 'data' => $res['data'] ?? []]); exit;
|
||||
}
|
||||
|
||||
$res = getProxmoxData($node['ip_address'], $node['token_id'], $node['token_secret'], $endpoint);
|
||||
echo json_encode(['success' => true, 'data' => $res['data'] ?? []]); exit;
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user