feat: Add IP address and DNS fields to module_vmware table
- Introduced `ip` and `dns` columns to the `module_vmware` table to store assigned IP addresses and DNS configurations. - Implemented `ChangePasswordViaSshJob` for secure password changes via SSH. - Created `ChangePasswordJob` for handling password changes during VM provisioning. - Developed `ChangePasswordViaVsphereJob` to reset VM guest OS passwords using PowerShell scripts executed on the vSphere host. - Added `SendVmCredentialsEmailJob` to send final VM credentials to customers. - Implemented `WaitVmReadyJob` to poll vSphere API until VMware Tools are running and guest IP is available. - Created `VmProvisionService` for managing VM provisioning tasks, including password generation and updates. - Developed `VsphereHostSshService` for executing PowerShell scripts on the vSphere host via SSH. - Added `IpPoolSeeder` to populate IP pools for VM service initialization.
This commit is contained in:
@@ -23,13 +23,16 @@ class VmController extends Controller
|
||||
/**
|
||||
* POST /v1/system/vm-power-on
|
||||
*
|
||||
* Body: { "product": <ModuleVmware.id> }
|
||||
* Body: { "product": <ModuleVmware.id|vmware_id|service_uuid> }
|
||||
*/
|
||||
public function powerOn(Request $request, PowerOnVMAction $action): JsonResponse
|
||||
{
|
||||
$validated = $request->validate(['product' => ['required', 'integer']]);
|
||||
$productId = $request->input('product');
|
||||
if (!$productId) {
|
||||
return response()->json(['success' => false, 'message' => 'Thiếu product id.'], 422);
|
||||
}
|
||||
|
||||
$vm = $this->resolveVm((int) $validated['product'], $request);
|
||||
$vm = $this->resolveVmById($productId, $request);
|
||||
if ($vm instanceof JsonResponse) {
|
||||
return $vm;
|
||||
}
|
||||
@@ -46,13 +49,16 @@ class VmController extends Controller
|
||||
/**
|
||||
* POST /v1/system/vm-power-off
|
||||
*
|
||||
* Body: { "product": <ModuleVmware.id> }
|
||||
* Body: { "product": <ModuleVmware.id|vmware_id|service_uuid> }
|
||||
*/
|
||||
public function powerOff(Request $request, PowerOffVMAction $action): JsonResponse
|
||||
{
|
||||
$validated = $request->validate(['product' => ['required', 'integer']]);
|
||||
$productId = $request->input('product');
|
||||
if (!$productId) {
|
||||
return response()->json(['success' => false, 'message' => 'Thiếu product id.'], 422);
|
||||
}
|
||||
|
||||
$vm = $this->resolveVm((int) $validated['product'], $request);
|
||||
$vm = $this->resolveVmById($productId, $request);
|
||||
if ($vm instanceof JsonResponse) {
|
||||
return $vm;
|
||||
}
|
||||
@@ -190,17 +196,17 @@ class VmController extends Controller
|
||||
* POST /v1/system/vm-change-port
|
||||
*
|
||||
* Body:
|
||||
* product int ModuleVmware.id
|
||||
* product int|string ModuleVmware.id|vmware_id|service_uuid
|
||||
* new_port int New RDP port (1024–65535)
|
||||
*/
|
||||
public function changePort(Request $request, ChangePortVMAction $action): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'product' => ['required', 'integer'],
|
||||
'product' => ['required'],
|
||||
'new_port' => ['required', 'integer', 'min:1024', 'max:65535'],
|
||||
]);
|
||||
|
||||
$vm = $this->resolveVm((int) $validated['product'], $request);
|
||||
$vm = $this->resolveVmById($validated['product'], $request);
|
||||
if ($vm instanceof JsonResponse) {
|
||||
return $vm;
|
||||
}
|
||||
@@ -239,25 +245,57 @@ class VmController extends Controller
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Load a ModuleVmware by ID, verify the authenticated user owns it.
|
||||
* 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 resolveVm(int $id, Request $request): ModuleVmware|JsonResponse
|
||||
private function resolveVmById(int|string $productId, Request $request): ModuleVmware|JsonResponse
|
||||
{
|
||||
$vm = ModuleVmware::with(['vCenter', 'ipAddress.host.datacenter.vCenter'])
|
||||
->find($id);
|
||||
$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'])
|
||||
->find((int) $productId);
|
||||
} 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) $request->user()->id) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise the array|string return value from Power ON/OFF actions.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user