initial commit
This commit is contained in:
104
app/Services/Hosting/Provisioning/VmidReservationService.php
Normal file
104
app/Services/Hosting/Provisioning/VmidReservationService.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?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',
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user