update rm deadcode

This commit is contained in:
baodev0
2026-09-27 11:42:40 +07:00
parent 82a71244ca
commit 3af59bd9c5
129 changed files with 5194 additions and 2698 deletions
@@ -10,10 +10,12 @@ use App\Http\Controllers\Controller;
use App\Http\Services\vCenter;
use App\Jobs\VirtualMachine\ChangeIpVMJob;
use App\Jobs\VirtualMachine\ChangeVmPasswordJob;
use App\Models\IpPool;
use App\Models\ModuleVmware;
use App\Models\Os;
use App\Models\Service;
use App\Services\ActivityLogger;
use App\Services\VirtualMachine\VmIpReservationService;
use App\Services\VmProvisionService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -21,9 +23,7 @@ use Illuminate\Support\Facades\Cache;
class VmController extends Controller
{
use ResolvesVm {
ResolvesVm::resolveVmById as resolveVmForClient;
}
use ResolvesVm;
public function __construct(protected ActivityLogger $activityLogger) {}
// -------------------------------------------------------------------------
@@ -114,43 +114,67 @@ class VmController extends Controller
// Change IP
// -------------------------------------------------------------------------
/**
* GET /v1/system/vm-ip-options
*
* Query: server_name string Service.server_name
* Lists free IP pool entries in the same network as the VM's current IP.
*/
public function ipOptions(Request $request): JsonResponse
{
$validated = $request->validate([
'server_name' => ['required', 'string', 'max:255'],
]);
$service = $this->findOwnedServiceByServerName($validated['server_name'], $request);
if ($service instanceof JsonResponse) {
return $service;
}
$vm = $service->orderItem?->order?->vmWare?->first();
if (!$vm) {
return response()->json(['success' => false, 'message' => 'Không tìm thấy VM cho dịch vụ này.'], 404);
}
$networkId = $vm->ipAddress?->module_network_id;
if (!$networkId) {
return response()->json(['success' => false, 'message' => 'Không xác định được mạng của VM.'], 422);
}
$ips = app(VmIpReservationService::class)->freeIpsInNetwork($networkId);
return response()->json([
'success' => true,
'data' => $ips->map(fn (IpPool $ip) => [
'ip_address' => $ip->ip_address,
'gateway' => $ip->gateway,
])->values(),
]);
}
/**
* POST /v1/system/vm-change-ip
*
* Body:
* server_name string Service.server_name (e.g. "xasdf.com.vnx")
* ip_address string New IP to assign
* gateway string (optional) Gateway — falls back to existing IP record
* ip_address string New IP to assign — must be a free IP from the VM's network pool
*/
/**
* Dispatches ChangeIpVMJob — returns immediately, runs async.
*/
public function changeIp(Request $request): JsonResponse
public function changeIp(Request $request, VmIpReservationService $ipReservation): JsonResponse
{
$validated = $request->validate([
'server_name' => ['required', 'string', 'max:255'],
'ip_address' => ['required', 'ip'],
'gateway' => ['nullable', 'ip'],
'dns' => ['nullable', 'ip'],
'guest_user' => ['required', 'string', 'max:255'],
'guest_password' => ['required', 'string', 'max:255'],
]);
$customer = $request->user();
// Look up Service by server_name + owner
// VM chain: Service → orderItem → order → vmWare (same as ServiceClientDetailResource)
$service = Service::with([
'orderItem.order.vmWare.vCenter',
'orderItem.order.vmWare.ipAddress.host.datacenter.vCenter',
'orderItem.os.osGroup',
])
->where('server_name', $validated['server_name'])
->where('customer_id', $customer->id)
->first();
if (!$service) {
return response()->json(['success' => false, 'message' => 'Không tìm thấy dịch vụ.'], 404);
$service = $this->findOwnedServiceByServerName($validated['server_name'], $request);
if ($service instanceof JsonResponse) {
return $service;
}
$vm = $service->orderItem?->order?->vmWare?->first();
@@ -159,29 +183,47 @@ class VmController extends Controller
return response()->json(['success' => false, 'message' => 'Không tìm thấy VM cho dịch vụ này.'], 404);
}
$networkId = $vm->ipAddress?->module_network_id;
if (!$networkId) {
return response()->json(['success' => false, 'message' => 'Không xác định được mạng của VM.'], 422);
}
$reservation = $ipReservation->reserveInNetwork($networkId, $validated['ip_address'], $service->id);
if (!$reservation) {
return response()->json(['success' => false, 'message' => 'IP không thuộc pool khả dụng hoặc đã được sử dụng.'], 422);
}
$oldIpPoolId = IpPool::where('module_network_id', $networkId)
->where('service_id', $service->id)
->where('status', 'assigned')
->where('id', '!=', $reservation['ip_pool_id'])
->value('id');
// Auto-detect OS type from the service's order item OS group
$osGroup = strtolower($service->orderItem?->os?->osGroup?->name ?? '');
$osType = (str_contains($osGroup, 'linux') || str_contains($osGroup, 'ubuntu') || str_contains($osGroup, 'centos'))
? 'linux'
: 'windows';
$gateway = $validated['gateway'] ?? '';
$dns = $validated['dns'] ?? '8.8.8.8';
$dns = $validated['dns'] ?? '8.8.8.8';
// ponytail: don't release — lock expires after 5 min while the async job runs
$lock = $this->acquireVmLock($vm, 300);
if (!$lock) {
$ipReservation->releaseByPoolId($reservation['ip_pool_id']);
return $this->vmLocked();
}
ChangeIpVMJob::dispatch(
$vm->id,
$validated['ip_address'],
$gateway,
$reservation['gateway'],
$osType,
$dns,
$validated['guest_user'],
$validated['guest_password'],
$reservation['ip_pool_id'],
$oldIpPoolId,
);
$this->activityLogger->log(
@@ -189,7 +231,7 @@ class VmController extends Controller
logName: 'VM',
description: "Customer {$request->user()->email} yêu cầu đổi IP VM: {$vm->name} → {$validated['ip_address']}",
subject: $vm,
newValues: ['ip_address' => $validated['ip_address'], 'gateway' => $gateway, 'os_type' => $osType],
newValues: ['ip_address' => $validated['ip_address'], 'gateway' => $reservation['gateway'], 'os_type' => $osType],
);
return response()->json([
@@ -198,6 +240,35 @@ class VmController extends Controller
]);
}
/**
* Look up a Service by server_name, verify ownership and active status.
* Returns JsonResponse on error, Service on success.
*/
private function findOwnedServiceByServerName(string $serverName, Request $request): Service|JsonResponse
{
$customer = $request->user();
// VM chain: Service → orderItem → order → vmWare (same as ServiceClientDetailResource)
$service = Service::with([
'orderItem.order.vmWare.vCenter',
'orderItem.order.vmWare.ipAddress.host.datacenter.vCenter',
'orderItem.os.osGroup',
])
->where('server_name', $serverName)
->where('customer_id', $customer->id)
->first();
if (!$service) {
return response()->json(['success' => false, 'message' => 'Không tìm thấy dịch vụ.'], 404);
}
if ($service->status !== 'active') {
return response()->json(['success' => false, 'message' => 'Dịch vụ không ở trạng thái hoạt động, không thể thao tác.'], 403);
}
return $service;
}
// -------------------------------------------------------------------------
// Change Port (RDP)
// -------------------------------------------------------------------------
@@ -319,7 +390,7 @@ class VmController extends Controller
return response()->json(['error' => true, 'message' => 'Thiếu product id'], 422);
}
$vm = $this->resolveVmForClient($productId, $request);
$vm = $this->resolveVmById($productId, $request);
if ($vm instanceof JsonResponse) {
return $vm;
}
@@ -431,7 +502,7 @@ class VmController extends Controller
return response()->json(['success' => false, 'message' => 'Thiếu product id.'], 422);
}
$vm = $this->resolveVmById($productId, $request);
$vm = $this->resolveVmById($productId, $request, requireActiveService: false);
if ($vm instanceof JsonResponse) {
return $vm;
}
@@ -462,60 +533,6 @@ class VmController extends Controller
// Shared helpers
// -------------------------------------------------------------------------
/**
* Load a ModuleVmware by ID (int), vmware_id (string), or Service UUID.
* Verify the authenticated user owns it.
* Returns JsonResponse on error, ModuleVmware on success.
*/
private function resolveVmById(int|string $productId, Request $request): ModuleVmware|JsonResponse
{
$customer = $request->user();
$vm = null;
// Check if it's a UUID (Service UUID)
if (is_string($productId) && preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $productId)) {
$service = Service::with('vmware.ipAddress.host.datacenter.vCenter', 'vmware.vCenter')
->where('uuid', $productId)
->where('customer_id', $customer->id)
->first();
if ($service && $service->vmware) {
$vm = $service->vmware;
}
} elseif (is_numeric($productId)) {
// Numeric ID
$vm = ModuleVmware::with(['vCenter', 'ipAddress.host.datacenter.vCenter'])
->where('id', (int) $productId)
->where('customer_id', $customer->id)
->first();
} else {
// vmware_id string (e.g., "vm-3238")
$vm = ModuleVmware::with(['vCenter', 'ipAddress.host.datacenter.vCenter'])
->where('vmware_id', $productId)
->where('customer_id', $customer->id)
->first();
}
if (!$vm) {
return response()->json(['success' => false, 'message' => 'Không tìm thấy VM.'], 404);
}
if ((int) $vm->customer_id !== (int) $customer->id) {
return response()->json(['success' => false, 'message' => 'Bạn không có quyền thao tác VM này.'], 403);
}
return $vm;
}
/**
* Load a ModuleVmware by ID, verify the authenticated user owns it.
* Returns JsonResponse on error, ModuleVmware on success.
* @deprecated Use resolveVmById instead for better ID format support
*/
private function resolveVm(int $id, Request $request): ModuleVmware|JsonResponse
{
return $this->resolveVmById($id, $request);
}
/** Try to acquire a per-VM operation lock. Returns null if already locked. */
private function acquireVmLock(ModuleVmware $vm, int $ttl = 60): ?\Illuminate\Contracts\Cache\Lock
{