105 lines
2.7 KiB
PHP
105 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Hosting\Provisioning;
|
|
|
|
use App\Exceptions\Hosting\ProvisioningException;
|
|
use App\Models\Customer;
|
|
use App\Models\VmidReservation;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class VmidReservationService
|
|
{
|
|
public function reserveForCustomer(Customer $customer): int
|
|
{
|
|
return DB::transaction(function () use ($customer) {
|
|
$vmid = $this->findNextAvailableVmid();
|
|
|
|
VmidReservation::query()->create([
|
|
'vmid' => $vmid,
|
|
'customer_id' => $customer->id,
|
|
'status' => 'reserved',
|
|
]);
|
|
|
|
return $vmid;
|
|
});
|
|
}
|
|
|
|
public function activate(int $vmid, Customer $customer): void
|
|
{
|
|
VmidReservation::query()
|
|
->where('vmid', $vmid)
|
|
->where('customer_id', $customer->id)
|
|
->update([
|
|
'status' => 'active',
|
|
'release_at' => null,
|
|
]);
|
|
}
|
|
|
|
public function scheduleRelease(int $vmid, ?Customer $customer = null): void
|
|
{
|
|
$hours = (int) config('hosting.vmid.release_after_hours', 48);
|
|
|
|
$query = VmidReservation::query()->where('vmid', $vmid);
|
|
|
|
if ($customer) {
|
|
$query->where('customer_id', $customer->id);
|
|
}
|
|
|
|
$query->update([
|
|
'status' => 'pending_release',
|
|
'release_at' => now()->addHours($hours),
|
|
]);
|
|
}
|
|
|
|
public function releaseDue(): int
|
|
{
|
|
$count = 0;
|
|
|
|
$due = VmidReservation::query()
|
|
->where('status', 'pending_release')
|
|
->where('release_at', '<=', now())
|
|
->get();
|
|
|
|
foreach ($due as $reservation) {
|
|
$reservation->update([
|
|
'status' => 'released',
|
|
'released_at' => now(),
|
|
]);
|
|
$count++;
|
|
}
|
|
|
|
return $count;
|
|
}
|
|
|
|
public function isVmidBlocked(int $vmid): bool
|
|
{
|
|
return VmidReservation::query()
|
|
->where('vmid', $vmid)
|
|
->whereIn('status', ['reserved', 'active', 'pending_release'])
|
|
->exists();
|
|
}
|
|
|
|
private function findNextAvailableVmid(): int
|
|
{
|
|
$start = (int) config('hosting.vmid.range_start', 2000);
|
|
$end = (int) config('hosting.vmid.range_end', 2999);
|
|
|
|
$blocked = VmidReservation::query()
|
|
->whereIn('status', ['reserved', 'active', 'pending_release'])
|
|
->pluck('vmid')
|
|
->flip()
|
|
->all();
|
|
|
|
for ($vmid = $start; $vmid <= $end; $vmid++) {
|
|
if (! isset($blocked[$vmid])) {
|
|
return $vmid;
|
|
}
|
|
}
|
|
|
|
throw new ProvisioningException(
|
|
"No free VMID in range {$start}-{$end}.",
|
|
step: 'reserving_vmid',
|
|
);
|
|
}
|
|
}
|