feat: enhance firewall log error handling in Proxmox component to provide clearer feedback on log loading issues and improve user experience
This commit is contained in:
@@ -24,6 +24,7 @@ class Firewall extends Component
|
||||
public array $availableIps = [];
|
||||
public bool $showDeleteModal = false;
|
||||
public ?int $deletingRulePos = null;
|
||||
public string $logError = '';
|
||||
|
||||
// Rule creation/editing
|
||||
public ?int $editingRulePos = null;
|
||||
@@ -89,9 +90,14 @@ class Firewall extends Component
|
||||
// Proxmox API token format: PVEAPIToken=USER@REALM!TOKENID=SECRET
|
||||
$authHeader = 'PVEAPIToken=' . $user . '!' . $tokenId . '=' . $secret;
|
||||
|
||||
// For firewall log endpoint, accept text/plain as well
|
||||
$acceptHeader = str_contains($url, '/firewall/log')
|
||||
? 'application/json, text/plain, */*'
|
||||
: 'application/json';
|
||||
|
||||
$request = Http::withHeaders([
|
||||
'Authorization' => $authHeader,
|
||||
'Accept' => 'application/json',
|
||||
'Accept' => $acceptHeader,
|
||||
])->withOptions([
|
||||
'verify' => true,
|
||||
]);
|
||||
@@ -787,7 +793,9 @@ class Firewall extends Component
|
||||
|
||||
public function loadFirewallLogs(): void
|
||||
{
|
||||
$this->logError = '';
|
||||
try {
|
||||
// Try the firewall log endpoint - Proxmox returns logs as text/plain, not JSON
|
||||
$response = $this->firewallRequest(
|
||||
'/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/firewall/log',
|
||||
'get',
|
||||
@@ -795,35 +803,52 @@ class Firewall extends Component
|
||||
);
|
||||
|
||||
if (!$response->successful()) {
|
||||
$errorData = $response->json();
|
||||
$errorMsg = $errorData['message'] ?? 'HTTP ' . $response->status();
|
||||
$this->logError = 'Failed to fetch logs: ' . $errorMsg;
|
||||
\Log::warning('Firewall log API request failed', [
|
||||
'status' => $response->status(),
|
||||
'body' => $response->body(),
|
||||
'server_id' => $this->server->id,
|
||||
'vm_id' => $this->server->vm_id
|
||||
]);
|
||||
$this->firewallLogs = [];
|
||||
return;
|
||||
}
|
||||
|
||||
$responseData = $response->json();
|
||||
// Proxmox firewall log endpoint returns plain text, not JSON
|
||||
$body = $response->body();
|
||||
$rawLogs = [];
|
||||
|
||||
if (isset($responseData['data']) && is_array($responseData['data'])) {
|
||||
$rawLogs = $responseData['data'];
|
||||
} elseif (is_array($responseData) && !isset($responseData['data'])) {
|
||||
$rawLogs = $responseData;
|
||||
if (!empty($body)) {
|
||||
// Split by newlines and filter empty lines
|
||||
$lines = explode("\n", trim($body));
|
||||
$rawLogs = array_filter($lines, function($line) {
|
||||
return !empty(trim($line));
|
||||
});
|
||||
}
|
||||
|
||||
// If still empty, try to get logs from the response body as text
|
||||
// If we got JSON instead, try to parse it
|
||||
if (empty($rawLogs)) {
|
||||
$body = $response->body();
|
||||
if (!empty($body) && is_string($body)) {
|
||||
$jsonData = json_decode($body, true);
|
||||
if (json_last_error() === JSON_ERROR_NONE && is_array($jsonData)) {
|
||||
$rawLogs = $jsonData['data'] ?? $jsonData;
|
||||
} else {
|
||||
$lines = explode("\n", trim($body));
|
||||
$rawLogs = array_filter($lines, function($line) {
|
||||
return !empty(trim($line));
|
||||
});
|
||||
try {
|
||||
$responseData = $response->json();
|
||||
if (isset($responseData['data']) && is_array($responseData['data'])) {
|
||||
$rawLogs = $responseData['data'];
|
||||
} elseif (is_array($responseData) && !isset($responseData['data'])) {
|
||||
$rawLogs = $responseData;
|
||||
}
|
||||
} catch (\Exception $jsonError) {
|
||||
// Not JSON, that's fine - we already tried plain text
|
||||
}
|
||||
}
|
||||
|
||||
\Log::debug('Firewall logs fetched', [
|
||||
'raw_count' => count($rawLogs),
|
||||
'body_length' => strlen($body),
|
||||
'content_type' => $response->header('Content-Type'),
|
||||
'sample' => !empty($rawLogs) ? (is_array($rawLogs[0]) ? json_encode($rawLogs[0]) : substr($rawLogs[0], 0, 200)) : null
|
||||
]);
|
||||
|
||||
$this->firewallLogs = [];
|
||||
|
||||
foreach ($rawLogs as $logEntry) {
|
||||
@@ -832,10 +857,12 @@ class Firewall extends Component
|
||||
if (is_string($logEntry)) {
|
||||
$logText = trim($logEntry);
|
||||
} elseif (is_array($logEntry)) {
|
||||
// Try common field names
|
||||
$logText = $logEntry['n'] ?? $logEntry['t'] ?? $logEntry['text'] ?? $logEntry['log'] ?? $logEntry['message'] ?? $logEntry['line'] ?? '';
|
||||
|
||||
// If still empty, try to get the first string value
|
||||
if (empty($logText)) {
|
||||
foreach ($logEntry as $value) {
|
||||
foreach ($logEntry as $key => $value) {
|
||||
if (is_string($value) && !empty(trim($value))) {
|
||||
$logText = trim($value);
|
||||
break;
|
||||
@@ -853,7 +880,31 @@ class Firewall extends Component
|
||||
$this->firewallLogs[] = $parsed;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->firewallLogs) && !empty($rawLogs)) {
|
||||
$this->logError = 'Logs received but could not be parsed. Please check that firewall logging is enabled in Proxmox.';
|
||||
} elseif (empty($this->firewallLogs)) {
|
||||
$this->logError = 'No firewall logs available. Ensure firewall logging is enabled in Proxmox (Datacenter > Firewall > Options).';
|
||||
}
|
||||
|
||||
\Log::debug('Firewall logs parsed', [
|
||||
'parsed_count' => count($this->firewallLogs)
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$errorMessage = $e->getMessage();
|
||||
if (method_exists($e, 'response') && $e->response()) {
|
||||
$errorData = $e->response()->json();
|
||||
if (isset($errorData['message'])) {
|
||||
$errorMessage = $errorData['message'];
|
||||
}
|
||||
}
|
||||
$this->logError = 'Error loading logs: ' . $errorMessage;
|
||||
\Log::error('Failed to load firewall logs', [
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
'server_id' => $this->server->id,
|
||||
'vm_id' => $this->server->vm_id
|
||||
]);
|
||||
$this->firewallLogs = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,6 +307,17 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if(!empty($logError))
|
||||
<div class="bg-warning/10 border border-warning/30 rounded-lg p-4 mb-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<x-ri-error-warning-line class="size-5 text-warning flex-shrink-0 mt-0.5" />
|
||||
<div class="flex-1">
|
||||
<p class="text-sm text-warning/90">{{ $logError }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(count($firewallLogs) > 0)
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse">
|
||||
@@ -347,10 +358,11 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
@elseif(empty($logError))
|
||||
<div class="text-center py-8 text-base/60">
|
||||
<x-ri-file-list-3-line class="size-12 mx-auto mb-3 opacity-50" />
|
||||
<p>No firewall logs available</p>
|
||||
<p class="text-xs mt-2">Ensure firewall logging is enabled in Proxmox (Datacenter > Firewall > Options)</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user