feat(vm): hoàn tiền khi cấp VM lỗi, theo dõi job queue, uuid dịch vụ cho ticket, chuẩn hoá RAM addon
- VmProvisionException/VmProvisionRefund xử lý lỗi cấp phát VM - QueueJobInspector + QueueMonitorController xem chi tiết job - Thêm service uuid cho ticket, thời lượng cho activity_logs - Migration chuẩn hoá RAM addon sang MB, trạng thái deleting cho snapshot Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
7136bec265
commit
62596d9063
@@ -51,90 +51,59 @@ class VMJobs implements ShouldQueue
|
||||
|
||||
$vcenter = $product->IpAddress->Host->Datacenter->vCenter;
|
||||
$serviceVCenter->setConnection($vcenter->host, $vcenter->token);
|
||||
$vmwareId = $product->vmware_id;
|
||||
$VirtualMachineStatus = null;
|
||||
$status = 1;
|
||||
|
||||
switch ($this->action) {
|
||||
case "Suspend":
|
||||
$VirtualMachineStatus = $serviceVCenter->SuspendVirtualMachine($product->vmware_id);
|
||||
if ($VirtualMachineStatus === "Login_Again") {
|
||||
$token = $serviceVCenter->loginServer($product->IpAddress->Host->Datacenter->vCenter);
|
||||
if ($token) {
|
||||
vCenter::where('id', $product->IpAddress->Host->Datacenter->vCenter->id)->update(['token' => $token]);
|
||||
$serviceVCenter->token = $token;
|
||||
}
|
||||
$VirtualMachineStatus = $serviceVCenter->SuspendVirtualMachine($product->vmware_id);
|
||||
$call = function (callable $action) use ($serviceVCenter, $vcenter) {
|
||||
$result = $action();
|
||||
if ($result === 'Login_Again') {
|
||||
$token = $serviceVCenter->loginServer($vcenter);
|
||||
if ($token) {
|
||||
vCenter::where('id', $vcenter->id)->update(['token' => $token]);
|
||||
$serviceVCenter->token = $token;
|
||||
}
|
||||
$result = $action();
|
||||
}
|
||||
|
||||
return $result;
|
||||
};
|
||||
|
||||
$powerState = fn () => $call(fn () => $serviceVCenter->CheckVirtualMachine($vmwareId))['power_state'] ?? null;
|
||||
|
||||
switch ($this->action) {
|
||||
case 'Suspend':
|
||||
$VirtualMachineStatus = $call(fn () => $serviceVCenter->SuspendVirtualMachine($vmwareId));
|
||||
$status = 2;
|
||||
break;
|
||||
|
||||
case "Reboot":
|
||||
$VirtualMachineStatus = $serviceVCenter->RebootVirtualMachine($product->vmware_id);
|
||||
if ($VirtualMachineStatus === "Login_Again") {
|
||||
$token = $serviceVCenter->loginServer($product->IpAddress->Host->Datacenter->vCenter);
|
||||
if ($token) {
|
||||
vCenter::where('id', $product->IpAddress->Host->Datacenter->vCenter->id)->update(['token' => $token]);
|
||||
$serviceVCenter->token = $token;
|
||||
}
|
||||
$VirtualMachineStatus = $serviceVCenter->RebootVirtualMachine($product->vmware_id);
|
||||
case 'Reboot':
|
||||
$VirtualMachineStatus = $call(fn () => $serviceVCenter->RebootVirtualMachine($product, $vmwareId));
|
||||
break;
|
||||
|
||||
case 'Start':
|
||||
if ($powerState() !== 'POWERED_ON') {
|
||||
$VirtualMachineStatus = $call(fn () => $serviceVCenter->StartVirtualMachine($product, $vmwareId));
|
||||
}
|
||||
break;
|
||||
|
||||
case "Start":
|
||||
$VirtualMachineStatus = $serviceVCenter->CheckVirtualMachine($product->vmware_id);
|
||||
if ($VirtualMachineStatus === "Login_Again") {
|
||||
$token = $serviceVCenter->loginServer($product->IpAddress->Host->Datacenter->vCenter);
|
||||
if ($token) {
|
||||
vCenter::where('id', $product->IpAddress->Host->Datacenter->vCenter->id)->update(['token' => $token]);
|
||||
$serviceVCenter->token = $token;
|
||||
}
|
||||
$VirtualMachineStatus = $serviceVCenter->CheckVirtualMachine($product->vmware_id);
|
||||
}
|
||||
if ($VirtualMachineStatus['data']['operations_ready'] === true) {
|
||||
break;
|
||||
}
|
||||
$VirtualMachineStatus = $serviceVCenter->StartVirtualMachine($product->vmware_id);
|
||||
break;
|
||||
|
||||
case "ShutdownGuest":
|
||||
$VirtualMachineStatus = $serviceVCenter->CheckVirtualMachine($product->vmware_id);
|
||||
if ($VirtualMachineStatus === "Login_Again") {
|
||||
$token = $serviceVCenter->loginServer($product->IpAddress->Host->Datacenter->vCenter);
|
||||
if ($token) {
|
||||
vCenter::where('id', $product->IpAddress->Host->Datacenter->vCenter->id)->update(['token' => $token]);
|
||||
$serviceVCenter->token = $token;
|
||||
}
|
||||
$VirtualMachineStatus = $serviceVCenter->CheckVirtualMachine($product->vmware_id);
|
||||
}
|
||||
if ($VirtualMachineStatus['data']['operations_ready'] === false) {
|
||||
$status = 0;
|
||||
break;
|
||||
}
|
||||
$VirtualMachineStatus = $serviceVCenter->ShutdownGuestVirtualMachine($product->vmware_id);
|
||||
case 'ShutdownGuest':
|
||||
$status = 0;
|
||||
if ($powerState() !== 'POWERED_OFF') {
|
||||
$VirtualMachineStatus = $call(fn () => $serviceVCenter->ShutdownGuestVirtualMachine($product, $vmwareId));
|
||||
}
|
||||
break;
|
||||
|
||||
case "PowerOff":
|
||||
$VirtualMachineStatus = $serviceVCenter->CheckVirtualMachine($product->vmware_id);
|
||||
if ($VirtualMachineStatus === "Login_Again") {
|
||||
$token = $serviceVCenter->loginServer($product->IpAddress->Host->Datacenter->vCenter);
|
||||
if ($token) {
|
||||
vCenter::where('id', $product->IpAddress->Host->Datacenter->vCenter->id)->update(['token' => $token]);
|
||||
$serviceVCenter->token = $token;
|
||||
}
|
||||
$VirtualMachineStatus = $serviceVCenter->CheckVirtualMachine($product->vmware_id);
|
||||
}
|
||||
if ($VirtualMachineStatus['data']['operations_ready'] === false) {
|
||||
$status = 0;
|
||||
break;
|
||||
}
|
||||
$VirtualMachineStatus = $serviceVCenter->PowerOffVirtualMachine($product->vmware_id);
|
||||
case 'PowerOff':
|
||||
$status = 0;
|
||||
if ($powerState() !== 'POWERED_OFF') {
|
||||
$VirtualMachineStatus = $call(fn () => $serviceVCenter->PowerOffVirtualMachine($vmwareId));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($VirtualMachineStatus && $VirtualMachineStatus['error']) {
|
||||
throw new \Exception(json_encode($VirtualMachineStatus['data']));
|
||||
if (is_array($VirtualMachineStatus) && ($VirtualMachineStatus['error'] ?? false)) {
|
||||
throw new \Exception(json_encode($VirtualMachineStatus['data'] ?? $VirtualMachineStatus));
|
||||
}
|
||||
|
||||
if ($this->update) {
|
||||
|
||||
@@ -6,13 +6,17 @@ namespace App\Jobs\VirtualMachine\Create;
|
||||
|
||||
use App\Http\Services\vCenter;
|
||||
use App\Jobs\VirtualMachine\Provision\UpdateVmConfigJob;
|
||||
use App\Exceptions\VmProvisionException;
|
||||
use App\Models\OrderItem;
|
||||
use App\Models\Service;
|
||||
use App\Models\VmProvisionLock;
|
||||
use App\Services\ActivityLogger;
|
||||
use App\Services\VirtualMachine\VmAddonResolver;
|
||||
use App\Services\VirtualMachine\VmInfrastructureResolver;
|
||||
use App\Services\VirtualMachine\VmIpReservationService;
|
||||
use App\Services\VirtualMachine\VmModuleService;
|
||||
use App\Services\VirtualMachine\VmNotificationService;
|
||||
use App\Services\VirtualMachine\VmProvisionRefund;
|
||||
use App\Services\VirtualMachine\VmProvisionLogger;
|
||||
use App\Services\VirtualMachine\VmServiceSyncService;
|
||||
use App\Services\VirtualMachine\VmVcenterErrorTranslator;
|
||||
@@ -51,6 +55,7 @@ class CreateVirtualMachineJob implements ShouldQueue
|
||||
VmNotificationService $notification,
|
||||
VmVcenterErrorTranslator $errorTranslator,
|
||||
VmIpReservationService $ipReservation,
|
||||
VmProvisionRefund $refund,
|
||||
): bool {
|
||||
$reservation = null;
|
||||
$ipPoolId = null;
|
||||
@@ -141,8 +146,9 @@ class CreateVirtualMachineJob implements ShouldQueue
|
||||
]);
|
||||
|
||||
if (is_array($result) && ($result['error'] ?? false)) {
|
||||
throw new RuntimeException(
|
||||
$errorTranslator->translate($result, $this->item->server_name)
|
||||
throw new VmProvisionException(
|
||||
$errorTranslator->translate($result, $this->item->server_name),
|
||||
$errorTranslator->detail($result),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -161,7 +167,11 @@ class CreateVirtualMachineJob implements ShouldQueue
|
||||
'vm_id' => $vmId,
|
||||
]);
|
||||
|
||||
$moduleVmware = $moduleService->create($this->item, $infra, $vmId);
|
||||
$moduleVmware = $moduleService->create($this->item, $infra, $vmId, [
|
||||
'cpu' => (int) $product->cpu + $addonData['cpu'],
|
||||
'ram_mb' => ((int) $product->ram + $addonData['ram']) * 1024,
|
||||
'disk_gb' => (int) $product->disk + $addonData['disk'],
|
||||
]);
|
||||
|
||||
$vmLogger->success('ModuleVmware created', [
|
||||
'module_vmware_id' => $moduleVmware->id,
|
||||
@@ -210,14 +220,31 @@ class CreateVirtualMachineJob implements ShouldQueue
|
||||
}
|
||||
|
||||
$lock?->update(['status' => 'failed']);
|
||||
Service::where('order_item_id', $this->item->id)
|
||||
->whereIn('status', ['pending', 'provisioning'])
|
||||
->update(['status' => 'failed']);
|
||||
|
||||
$adminDetail = $e instanceof VmProvisionException ? $e->adminDetail : $e->getMessage();
|
||||
|
||||
$vmLogger->exception('Create VM job failed', $e, [
|
||||
'order_item_id' => $this->item->id,
|
||||
'is_retry' => $this->isRetry,
|
||||
'admin_detail' => $adminDetail,
|
||||
]);
|
||||
|
||||
$failedService = Service::where('order_item_id', $this->item->id)->first();
|
||||
if ($failedService) {
|
||||
app(ActivityLogger::class)->log(
|
||||
'provision_failed',
|
||||
'service',
|
||||
'Khởi tạo máy ảo thất bại — ' . $adminDetail,
|
||||
$failedService,
|
||||
);
|
||||
}
|
||||
|
||||
if (!$this->isRetry) {
|
||||
$notification->failed($this->item, $e->getMessage());
|
||||
$refunded = $refund->refund($this->item, $e->getMessage());
|
||||
$notification->failed($this->item, $e->getMessage() . ($refunded ? ' (đã tự động hoàn tiền cho khách)' : ''));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -206,8 +206,9 @@ class UpdateVmConfigJob implements ShouldQueue
|
||||
'output' => trim($output),
|
||||
]);
|
||||
|
||||
$moduleVmware->update(['cpu' => $totalCpu, 'ram_mb' => $totalRam * 1024]);
|
||||
|
||||
if ($isManualOverride) {
|
||||
$moduleVmware->update(['cpu' => $totalCpu, 'ram_mb' => $totalRam * 1024]);
|
||||
$this->syncServiceAddons($moduleVmware, $totalCpu, $totalRam, $logger);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -160,6 +160,10 @@ class RemoveSnapshot implements ShouldQueue
|
||||
|
||||
public function failed(\Throwable $exception)
|
||||
{
|
||||
ModuleSnapshot::where('id', $this->snapshotId)
|
||||
->where('status', 'deleting')
|
||||
->update(['status' => 'success', 'error_message' => $exception->getMessage()]);
|
||||
|
||||
Log::error('❌ Job RemoveSnapshot failed', [
|
||||
'product_id' => $this->productId,
|
||||
'snapshot_id' => $this->snapshotId,
|
||||
|
||||
Reference in New Issue
Block a user