Files
Virtnet.bond/extensions/Servers/Proxmox/Livewire/Server.php

175 lines
6.2 KiB
PHP

<?php
namespace Paymenter\Extensions\Servers\Proxmox\Livewire;
use Paymenter\Extensions\Servers\Proxmox\Models\Server as ServerModel;
use Paymenter\Extensions\Servers\Proxmox\Models\ServerStatistics;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
class Server extends Component
{
public function mount(ServerModel $server): void
{
parent::mount($server);
// Check and enforce bandwidth throttling if exceeded
$this->checkAndEnforceBandwidthLimit();
}
public function getMonthlyTrafficProperty()
{
$startOfMonth = Carbon::now()->startOfMonth();
// Get the earliest and latest statistics for this month
$firstStat = $this->server->statistics()
->where('DateTime', '>=', $startOfMonth)
->orderBy('DateTime', 'asc')
->first();
$latestStat = $this->server->statistics()
->where('DateTime', '>=', $startOfMonth)
->orderBy('DateTime', 'desc')
->first();
if (!$firstStat || !$latestStat) {
return 0;
}
// Calculate total traffic (in + out) for the month
$netinDiff = max(0, $latestStat->netin - $firstStat->netin);
$netoutDiff = max(0, $latestStat->netout - $firstStat->netout);
$totalBytes = $netinDiff + $netoutDiff;
// Convert to GiB
return round($totalBytes / (1024 * 1024 * 1024), 2);
}
public function getBandwidthThreshold95Property()
{
// Cache for 15 minutes to avoid recalculating for every server
return Cache::remember('bandwidth_threshold_95_' . Carbon::now()->format('Y-m'), 15, function () {
$startOfMonth = Carbon::now()->startOfMonth();
// Get all servers
$allServers = ServerModel::all();
if ($allServers->isEmpty()) {
return 10; // Minimum threshold of 10 GiB
}
$totalTraffic = 0;
$serverCount = 0;
foreach ($allServers as $server) {
// Get the earliest and latest statistics for this month for each server
$firstStat = ServerStatistics::where('server_id', $server->id)
->where('DateTime', '>=', $startOfMonth)
->orderBy('DateTime', 'asc')
->first();
$latestStat = ServerStatistics::where('server_id', $server->id)
->where('DateTime', '>=', $startOfMonth)
->orderBy('DateTime', 'desc')
->first();
if ($firstStat && $latestStat) {
// Calculate total traffic (in + out) for the month
$netinDiff = max(0, $latestStat->netin - $firstStat->netin);
$netoutDiff = max(0, $latestStat->netout - $firstStat->netout);
$totalBytes = $netinDiff + $netoutDiff;
// Convert to GiB and add to total
$totalTraffic += $totalBytes / (1024 * 1024 * 1024);
$serverCount++;
}
}
if ($serverCount === 0) {
return 10; // Minimum threshold of 10 GiB
}
// Calculate average bandwidth across all servers
$averageBandwidth = $totalTraffic / $serverCount;
// Calculate 95% of average
$threshold95Percent = $averageBandwidth * 0.95;
// Return the maximum of 95% average or 10 GiB minimum
return round(max($threshold95Percent, 10), 2);
});
}
protected function checkAndEnforceBandwidthLimit()
{
$monthlyTraffic = $this->monthlyTraffic;
$threshold = $this->bandwidthThreshold95;
// Check if bandwidth is exceeded
if ($monthlyTraffic > $threshold) {
// Throttle the server to 1 MiB/s
$this->throttleServerBandwidth();
}
}
protected function throttleServerBandwidth()
{
try {
$proxmox = new \Paymenter\Extensions\Servers\Proxmox\Proxmox;
// Get current VM config
$config = $proxmox->request('/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/config')->json()['data'];
$updates = [];
// Update all network interfaces to rate limit of 1 MiB/s
foreach ($config as $key => $value) {
if (preg_match('/^net\d+$/', $key)) {
// Parse existing network config
$parts = explode(',', $value);
$newParts = [];
$hasRate = false;
foreach ($parts as $part) {
if (strpos($part, 'rate=') === 0) {
// Replace existing rate
$newParts[] = 'rate=1';
$hasRate = true;
} else {
$newParts[] = $part;
}
}
// Add rate if not present
if (!$hasRate) {
$newParts[] = 'rate=1';
}
$updates[$key] = implode(',', $newParts);
}
}
// Apply the updates if any network interfaces were found
if (!empty($updates)) {
$proxmox->request('/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/config', 'put', $updates);
}
} catch (\Throwable $e) {
// Log the error but don't fail the page load
\Log::error('Failed to throttle bandwidth for server ' . $this->server->id, [
'error' => $e->getMessage(),
'server_id' => $this->server->id,
]);
}
}
public function render()
{
return view('proxmox::server');
}
public function placeholder(array $params = [])
{
return view('proxmox::serverplaceholder', $params);
}
}