update show ip & reinstall vps 50%
This commit is contained in:
@@ -11,11 +11,13 @@ use App\Http\Services\vCenter;
|
||||
use App\Models\ModuleSnapshot;
|
||||
use App\Models\ModuleVmware;
|
||||
use App\Models\Order;
|
||||
use App\Models\Os;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Validator as ValidatorInstance;
|
||||
|
||||
class ServiceController extends Controller
|
||||
{
|
||||
@@ -146,8 +148,11 @@ class ServiceController extends Controller
|
||||
|
||||
// Lấy thông tin IP
|
||||
$ipAddress = 'N/A';
|
||||
if ($ipInfo['error'] === false && !empty($ipInfo['data']['ip_addresses'])) {
|
||||
$ipAddress = $ipInfo['data']['ip_addresses'][0] ?? 'N/A';
|
||||
if ($ipInfo['error'] === false && !empty($ipInfo['data']['ip_address'])) {
|
||||
$ipAddress = $ipInfo['data']['ip_address'] ?? 'N/A';
|
||||
} elseif ($ipInfo['error'] === false && isset($ipInfo['data']['value']['ip_address'])) {
|
||||
// Fallback for nested structure
|
||||
$ipAddress = $ipInfo['data']['value']['ip_address'] ?? 'N/A';
|
||||
}
|
||||
|
||||
// Tính toán thông tin phần cứng
|
||||
@@ -414,7 +419,6 @@ class ServiceController extends Controller
|
||||
->onQueue('snapshots');
|
||||
|
||||
return redirect()->back()->with('success', 'Đã gửi yêu cầu tạo snapshot. Quá trình sẽ mất 3-5 phút, vui lòng chờ đợi.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('❌ Lỗi khi tạo snapshot', [
|
||||
'product_id' => $request->product_id ?? 'not_provided',
|
||||
@@ -527,7 +531,6 @@ class ServiceController extends Controller
|
||||
'data' => $responseData,
|
||||
'cached' => false
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Lỗi khi lấy danh sách snapshot', [
|
||||
'user_id' => $user->id ?? 'guest',
|
||||
@@ -618,7 +621,6 @@ class ServiceController extends Controller
|
||||
'error' => false,
|
||||
'message' => 'Đã gửi yêu cầu xóa snapshot. Quá trình sẽ mất 1-2 phút, vui lòng chờ đợi.'
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('❌ Lỗi khi xóa snapshot', [
|
||||
'product_id' => $request->product_id ?? 'not_provided',
|
||||
@@ -710,7 +712,6 @@ class ServiceController extends Controller
|
||||
'error' => false,
|
||||
'message' => 'Đã gửi yêu cầu khôi phục snapshot. Quá trình sẽ mất 2-3 phút, vui lòng chờ đợi.'
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('❌ Lỗi khi khôi phục snapshot', [
|
||||
'product_id' => $request->product_id ?? 'not_provided',
|
||||
@@ -930,6 +931,183 @@ class ServiceController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function reinstallVM(Request $request, vCenter $vCenterService)
|
||||
{
|
||||
try {
|
||||
// Debug: Log request data
|
||||
Log::info('reinstallVM called', [
|
||||
'request_data' => $request->all(),
|
||||
'user_id' => customer()?->id ?? 'not_logged_in'
|
||||
]);
|
||||
|
||||
$user = customer();
|
||||
if (!$user) {
|
||||
Log::warning('User not logged in for reinstallVM');
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => __('Chưa đăng nhập. Vui lòng đăng nhập để sử dụng tính năng này.')
|
||||
], 401);
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'invoice_id' => 'required|integer',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
Log::warning('Validation failed for reinstallVM', [
|
||||
'errors' => $validator->errors()->toArray()
|
||||
]);
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => __('Dữ liệu không hợp lệ'),
|
||||
'errors' => $validator->errors()
|
||||
], 422);
|
||||
}
|
||||
|
||||
// Debug: Log invoice lookup
|
||||
Log::info('Looking for invoice', ['invoice_id' => $request->invoice_id]);
|
||||
|
||||
$invoice = Invoice::find($request->invoice_id);
|
||||
|
||||
// Debug: Log invoice result
|
||||
Log::info('Invoice lookup result', [
|
||||
'invoice_id' => $request->invoice_id,
|
||||
'found' => $invoice ? 'yes' : 'no',
|
||||
'invoice_data' => $invoice ? $invoice->toArray() : null
|
||||
]);
|
||||
|
||||
if (!$invoice) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => __('Không tìm thấy hóa đơn')
|
||||
], 404);
|
||||
}
|
||||
|
||||
// Debug: Log product lookup
|
||||
$invoiceItem = $invoice->invoiceItem->first();
|
||||
Log::info('Invoice item lookup', [
|
||||
'invoice_item_found' => $invoiceItem ? 'yes' : 'no',
|
||||
'invoice_item_data' => $invoiceItem ? $invoiceItem->toArray() : null
|
||||
]);
|
||||
|
||||
$productId = $invoiceItem?->getProductAttribute()?->id;
|
||||
Log::info('Product lookup', [
|
||||
'product_id' => $productId,
|
||||
'product_data' => $invoiceItem?->getProductAttribute()?->toArray() ?? null
|
||||
]);
|
||||
|
||||
$vmware = $productId;
|
||||
$osId = $request->os_id;
|
||||
$userId = $user->id;
|
||||
|
||||
Log::info('VM lookup parameters', [
|
||||
'vmware_id' => $vmware?->vmware_id ?? 'null',
|
||||
'os_id' => $osId,
|
||||
'user_id' => $userId
|
||||
]);
|
||||
|
||||
// Tìm product và kiểm tra quyền sở hữu
|
||||
$vm = ModuleVmware::where('vmware_id', $vmware->vmware_id)
|
||||
->where('customer_id', $userId)
|
||||
->first();
|
||||
|
||||
Log::info('VM lookup result', [
|
||||
'vm_found' => $vm ? 'yes' : 'no',
|
||||
'vm_data' => $vm ? $vm->toArray() : null
|
||||
]);
|
||||
if (!$vm) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => __('Không tìm thấy VPS hoặc bạn không có quyền truy cập')
|
||||
], 404);
|
||||
}
|
||||
|
||||
// Kiểm tra OS có tồn tại và hợp lệ không
|
||||
$os = Os::find($osId);
|
||||
if (!$os) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => __('Hệ điều hành không tồn tại')
|
||||
], 404);
|
||||
}
|
||||
|
||||
// Kiểm tra OS có được phép cho VPS này không
|
||||
$allowedOs = $vm->operatingSystems()->where('os.id', $osId)->first();
|
||||
if (!$allowedOs) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => __('Hệ điều hành này không được phép cho VPS này')
|
||||
], 403);
|
||||
}
|
||||
|
||||
// Debug: Log before vCenter call
|
||||
Log::info('About to call vCenter DeleteVirtualMachine', [
|
||||
'vmware_id' => $vm->vmware_id,
|
||||
'os_id' => $osId
|
||||
]);
|
||||
|
||||
// Gọi vCenter service để xóa VM
|
||||
$result = $vCenterService->DeleteVirtualMachine($vm->vmware_id);
|
||||
|
||||
// Debug: Log vCenter result
|
||||
Log::info('vCenter DeleteVirtualMachine result', [
|
||||
'result' => $result,
|
||||
'is_array' => is_array($result),
|
||||
'has_error_key' => is_array($result) && isset($result['error']),
|
||||
'error_value' => is_array($result) ? ($result['error'] ?? 'not_set') : 'not_array'
|
||||
]);
|
||||
|
||||
if (is_array($result) && isset($result['error']) && $result['error'] === false) {
|
||||
// Cập nhật OS trong database
|
||||
$vm->update([
|
||||
'os_id' => $osId
|
||||
]);
|
||||
|
||||
// Clear VM info cache
|
||||
Cache::forget('vm_info_' . $vm->vmware_id);
|
||||
|
||||
// Log hoạt động
|
||||
Log::info('VM reinstall initiated', [
|
||||
'user_id' => $userId,
|
||||
'product_id' => $vm->id,
|
||||
'old_os_id' => $vm->os_id,
|
||||
'new_os_id' => $osId,
|
||||
'os_name' => $os->version
|
||||
]);
|
||||
|
||||
Log::info('Returning success response');
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => __('Yêu cầu cài lại máy ảo đã được gửi thành công. Quá trình sẽ mất 5-10 phút.')
|
||||
]);
|
||||
} else {
|
||||
$msg = is_array($result) && isset($result['data']) ? $result['data'] : __('Không thể cài lại máy ảo');
|
||||
Log::warning('vCenter call failed', [
|
||||
'result' => $result,
|
||||
'message' => $msg
|
||||
]);
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $msg
|
||||
], 500);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Lỗi khi cài lại máy ảo', [
|
||||
'user_id' => $user->id ?? 'guest',
|
||||
'product_id' => $request->product_id ?? 'not_provided',
|
||||
'os_id' => $request->os_id ?? 'not_provided',
|
||||
'error' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
]);
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => __('Có lỗi xảy ra khi cài lại máy ảo')
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize input data
|
||||
*/
|
||||
@@ -1016,7 +1194,6 @@ class ServiceController extends Controller
|
||||
}
|
||||
|
||||
return $result['data'] ?? [];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Lỗi khi lấy snapshot từ vCenter', [
|
||||
'product_id' => $product->id,
|
||||
|
||||
@@ -7,6 +7,10 @@ use App\Models\Os;
|
||||
use App\Models\OsGroup;
|
||||
use App\Models\VPS;
|
||||
use App\Models\InvoiceItem;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\ModuleVmware;
|
||||
|
||||
class VPSReinstallModal extends Component
|
||||
{
|
||||
@@ -17,6 +21,13 @@ class VPSReinstallModal extends Component
|
||||
public $operatingSystems = [];
|
||||
public $currentOs;
|
||||
public $invoiceId;
|
||||
public $isLoading = false;
|
||||
public $selectedOsDetails = null;
|
||||
public $vpsInfo = null;
|
||||
public $moduleVmware = null;
|
||||
public $vpsIpAddress = null;
|
||||
public $invoiceItem = null;
|
||||
public $invoice = null;
|
||||
|
||||
protected $listeners = ['showOsModal' => 'loadOsData'];
|
||||
|
||||
@@ -24,6 +35,7 @@ class VPSReinstallModal extends Component
|
||||
{
|
||||
$this->productId = $productId;
|
||||
$this->invoiceId = $invoiceId;
|
||||
$this->operatingSystems = collect(); // Initialize as empty collection
|
||||
if ($productId) {
|
||||
$this->loadOsData($productId);
|
||||
}
|
||||
@@ -32,70 +44,304 @@ class VPSReinstallModal extends Component
|
||||
public function loadOsData($productId)
|
||||
{
|
||||
$this->productId = $productId;
|
||||
|
||||
// Get the VPS product
|
||||
$vps = VPS::with('operatingSystems.osGroup')->find($productId);
|
||||
|
||||
if (!$vps) {
|
||||
return;
|
||||
}
|
||||
$this->isLoading = true;
|
||||
|
||||
// Get OS groups that are assigned to this VPS product
|
||||
$osGroupIds = $vps->operatingSystems->pluck('osGroup.id')->filter()->unique();
|
||||
|
||||
$this->osGroups = OsGroup::with(['os' => function($query) use ($vps) {
|
||||
// Only get OS versions that are assigned to this specific VPS product
|
||||
$query->whereHas('vpsProducts', function($q) use ($vps) {
|
||||
$q->where('product_id', $vps->id)
|
||||
->where('product_type', 4);
|
||||
})->where('status', 1);
|
||||
}])
|
||||
->whereIn('id', $osGroupIds)
|
||||
->where('status', 1)
|
||||
->get();
|
||||
try {
|
||||
// Get the VPS product
|
||||
$vps = VPS::with('operatingSystems.osGroup')->find($productId);
|
||||
|
||||
// Get current OS from invoice_item
|
||||
if ($this->invoiceId) {
|
||||
$invoiceItem = InvoiceItem::where('invoice_id', $this->invoiceId)
|
||||
->where('product_id', $productId)
|
||||
->where('product_type', 4)
|
||||
->with('os.osGroup')
|
||||
->first();
|
||||
if (!$vps) {
|
||||
session()->flash('error', __('Không tìm thấy thông tin VPS.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Store VPS info for confirmation message
|
||||
$this->vpsInfo = $vps;
|
||||
|
||||
// Get OS groups that are assigned to this VPS product
|
||||
$osGroupIds = $vps->operatingSystems->pluck('osGroup.id')->filter()->unique();
|
||||
|
||||
$this->osGroups = OsGroup::with(['os' => function ($query) use ($vps) {
|
||||
// Only get OS versions that are assigned to this specific VPS product
|
||||
$query->whereHas('vpsProducts', function ($q) use ($vps) {
|
||||
$q->where('product_id', $vps->id)
|
||||
->where('product_type', 4);
|
||||
})->where('status', 1);
|
||||
}])
|
||||
->whereIn('id', $osGroupIds)
|
||||
->where('status', 1)
|
||||
->get();
|
||||
|
||||
// Get current OS and ModuleVmware info from invoice_item
|
||||
if ($this->invoiceId) {
|
||||
$this->invoiceItem = InvoiceItem::where('invoice_id', $this->invoiceId)
|
||||
->where('product_id', $productId)
|
||||
->where('product_type', 4)
|
||||
->with('os.osGroup')
|
||||
->first();
|
||||
|
||||
$this->currentOs = $this->invoiceItem?->os;
|
||||
|
||||
$this->currentOs = $invoiceItem?->os;
|
||||
// Debug InvoiceItem info first
|
||||
Log::info('InvoiceItem debug info', [
|
||||
'invoice_id' => $this->invoiceId,
|
||||
'product_id' => $productId,
|
||||
'product_type' => 4,
|
||||
'invoice_item_found' => $this->invoiceItem ? 'yes' : 'no',
|
||||
'invoice_item_id' => $this->invoiceItem?->id ?? 'null',
|
||||
'invoice_item_relid' => $this->invoiceItem?->relid ?? 'null',
|
||||
'invoice_item_type_id' => $this->invoiceItem?->type_id ?? 'null',
|
||||
'invoice_item_product_id' => $this->invoiceItem?->product_id ?? 'null',
|
||||
'invoice_item_product_type' => $this->invoiceItem?->product_type ?? 'null'
|
||||
]);
|
||||
|
||||
// Get ModuleVmware info to access IP address
|
||||
if ($this->invoiceItem) {
|
||||
// Try to get ModuleVmware directly using invoice_id and customer_id
|
||||
$this->invoice = Invoice::find($this->invoiceId);
|
||||
if ($this->invoice && $this->invoice->customer_id) {
|
||||
$this->moduleVmware = ModuleVmware::where('customer_id', $this->invoice->customer_id)
|
||||
->where('order_id', $this->invoiceId)
|
||||
->with('ipAddress')
|
||||
->first();
|
||||
|
||||
// If not found by order_id, try to find by customer_id and product info
|
||||
if (!$this->moduleVmware) {
|
||||
$this->moduleVmware = ModuleVmware::where('customer_id', $this->invoice->customer_id)
|
||||
->with('ipAddress')
|
||||
->first();
|
||||
}
|
||||
}
|
||||
|
||||
// Try to get IP from vCenter API first, fallback to database
|
||||
$this->vpsIpAddress = $this->getIPFromVCenter() ?? $this->moduleVmware?->ipAddress?->ip ?? null;
|
||||
|
||||
// Debug ModuleVmware info
|
||||
Log::info('ModuleVmware debug info', [
|
||||
'invoice_item_id' => $this->invoiceItem->id,
|
||||
'invoice_item_relid' => $this->invoiceItem->relid,
|
||||
'invoice_item_type_id' => $this->invoiceItem->type_id,
|
||||
'invoice_customer_id' => $this->invoice?->customer_id ?? 'null',
|
||||
'module_vmware' => $this->moduleVmware ? 'found' : 'not_found',
|
||||
'module_vmware_id' => $this->moduleVmware?->id ?? 'null',
|
||||
'module_vmware_name' => $this->moduleVmware?->name ?? 'null',
|
||||
'module_vmware_customer_id' => $this->moduleVmware?->customer_id ?? 'null',
|
||||
'module_ip_address_id' => $this->moduleVmware?->module_ip_address_id ?? 'null',
|
||||
'ip_address_relationship' => $this->moduleVmware?->ipAddress ? 'found' : 'not_found',
|
||||
'ip_address_from_db' => $this->moduleVmware?->ipAddress?->ip ?? 'null',
|
||||
'ip_address_from_vcenter' => $this->vpsIpAddress ?? 'null'
|
||||
]);
|
||||
} else {
|
||||
Log::warning('InvoiceItem not found', [
|
||||
'invoice_id' => $this->invoiceId,
|
||||
'product_id' => $productId,
|
||||
'product_type' => 4
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Log::info('OS data loaded successfully', [
|
||||
'product_id' => $productId,
|
||||
'os_groups_count' => is_object($this->osGroups) ? $this->osGroups->count() : count($this->osGroups),
|
||||
'current_os' => $this->currentOs ? $this->currentOs->id : null,
|
||||
'module_vmware_id' => $this->moduleVmware ? $this->moduleVmware->id : null,
|
||||
'ip_address' => $this->moduleVmware?->ipAddress?->ip ?? 'N/A'
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error loading OS data', [
|
||||
'product_id' => $productId,
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
session()->flash('error', __('Có lỗi xảy ra khi tải dữ liệu hệ điều hành.'));
|
||||
} finally {
|
||||
$this->isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedSelectedOsGroupId($value)
|
||||
{
|
||||
// Reset selected OS when changing group
|
||||
$this->selectedOsId = null;
|
||||
$this->selectedOsDetails = null;
|
||||
|
||||
$this->isLoading = true;
|
||||
|
||||
try {
|
||||
if ($value) {
|
||||
$this->operatingSystems = Os::where('os_group_id', $value)
|
||||
->where('status', 1)
|
||||
->whereHas('vpsProducts', function ($query) {
|
||||
$query->where('product_id', $this->productId)
|
||||
->where('product_type', 4);
|
||||
})
|
||||
->with('osGroup')
|
||||
->get();
|
||||
|
||||
Log::info('Operating systems loaded for group', [
|
||||
'os_group_id' => $value,
|
||||
'os_count' => is_object($this->operatingSystems) ? $this->operatingSystems->count() : count($this->operatingSystems),
|
||||
'selected_os_id' => $this->selectedOsId
|
||||
]);
|
||||
} else {
|
||||
$this->operatingSystems = collect();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error loading operating systems', [
|
||||
'os_group_id' => $value,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
session()->flash('error', __('Có lỗi xảy ra khi tải danh sách phiên bản hệ điều hành.'));
|
||||
$this->operatingSystems = collect();
|
||||
} finally {
|
||||
$this->isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedSelectedOsId($value)
|
||||
{
|
||||
Log::info('Selected OS ID updated', [
|
||||
'selected_os_id' => $value,
|
||||
'is_loading' => $this->isLoading
|
||||
]);
|
||||
|
||||
// Store selected OS details for confirmation message
|
||||
if ($value) {
|
||||
$this->operatingSystems = Os::where('os_group_id', $value)
|
||||
->where('status', 1)
|
||||
->whereHas('vpsProducts', function($query) {
|
||||
$query->where('product_id', $this->productId)
|
||||
->where('product_type', 4);
|
||||
})
|
||||
->get();
|
||||
$this->selectedOsDetails = Os::with('osGroup')->find($value);
|
||||
|
||||
Log::info('OS details loaded', [
|
||||
'os_id' => $value,
|
||||
'os_name' => $this->selectedOsDetails?->osGroup?->name ?? 'null',
|
||||
'os_version' => $this->selectedOsDetails?->version ?? 'null'
|
||||
]);
|
||||
} else {
|
||||
$this->operatingSystems = [];
|
||||
$this->selectedOsDetails = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function confirmReinstall()
|
||||
{
|
||||
Log::info('confirmReinstall called', [
|
||||
'selected_os_id' => $this->selectedOsId,
|
||||
'invoice_id' => $this->invoiceId,
|
||||
'is_loading' => $this->isLoading
|
||||
]);
|
||||
|
||||
if (!$this->selectedOsId) {
|
||||
session()->flash('error', __('Please select an operating system.'));
|
||||
session()->flash('error', __('Vui lòng chọn hệ điều hành.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Here you would implement the reinstall logic
|
||||
// For now, just show a success message
|
||||
session()->flash('success', __('Operating system reinstall initiated.'));
|
||||
|
||||
// Close modal
|
||||
$this->dispatchBrowserEvent('close-modal', ['name' => 'reinstall-vm']);
|
||||
if (!$this->invoiceId) {
|
||||
session()->flash('error', __('Thiếu thông tin hóa đơn.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->isLoading = true;
|
||||
|
||||
try {
|
||||
$response = Http::withoutVerifying()
|
||||
->withHeaders([
|
||||
'X-CSRF-TOKEN' => csrf_token(),
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
])
|
||||
->post(route('service.reinstall.vm'), [
|
||||
'invoice_id' => $this->invoiceId,
|
||||
'os_id' => $this->selectedOsId,
|
||||
]);
|
||||
|
||||
Log::info('Reinstall response', [
|
||||
'status' => $response->status(),
|
||||
'body' => $response->body()
|
||||
]);
|
||||
|
||||
if ($response->successful()) {
|
||||
session()->flash('success', __('Yêu cầu cài lại hệ điều hành đã được gửi thành công.'));
|
||||
$this->dispatch('close-modal', ['name' => 'reinstall-vm']);
|
||||
} else {
|
||||
$errorMessage = $response->json('message') ?? __('Có lỗi xảy ra khi gửi yêu cầu.');
|
||||
session()->flash('error', $errorMessage);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error during reinstall request', [
|
||||
'invoice_id' => $this->invoiceId,
|
||||
'os_id' => $this->selectedOsId,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
session()->flash('error', __('Có lỗi xảy ra khi gửi yêu cầu cài lại.'));
|
||||
} finally {
|
||||
$this->isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IP address from vCenter API
|
||||
*/
|
||||
private function getIPFromVCenter()
|
||||
{
|
||||
try {
|
||||
if (!$this->moduleVmware || !$this->moduleVmware->vmware_id) {
|
||||
Log::warning('No ModuleVmware or vmware_id found for vCenter IP lookup');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get vCenter configuration from ModuleVmware
|
||||
$vcenter = $this->moduleVmware->ipAddress?->host?->datacenter?->vCenter;
|
||||
if (!$vcenter) {
|
||||
Log::warning('No vCenter configuration found for ModuleVmware', [
|
||||
'module_vmware_id' => $this->moduleVmware->id,
|
||||
'vmware_id' => $this->moduleVmware->vmware_id
|
||||
]);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Initialize vCenter service
|
||||
$vCenterService = new \App\Http\Services\vCenter();
|
||||
|
||||
// Login to vCenter
|
||||
$loginSuccess = $vCenterService->loginServer($vcenter);
|
||||
if (!$loginSuccess) {
|
||||
Log::warning('Failed to login to vCenter for IP lookup', [
|
||||
'vmware_id' => $this->moduleVmware->vmware_id,
|
||||
'vcenter_id' => $vcenter->id
|
||||
]);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get IP address from vCenter
|
||||
$ipInfo = $vCenterService->GetIPAddressVirtualMachine($this->moduleVmware->vmware_id);
|
||||
|
||||
Log::info('vCenter IP lookup result', [
|
||||
'vmware_id' => $this->moduleVmware->vmware_id,
|
||||
'ip_info' => $ipInfo
|
||||
]);
|
||||
|
||||
if (is_array($ipInfo) && isset($ipInfo['error']) && $ipInfo['error'] === false) {
|
||||
// Try different possible structures
|
||||
if (isset($ipInfo['data']['ip_address'])) {
|
||||
return $ipInfo['data']['ip_address'];
|
||||
} elseif (isset($ipInfo['data']['value']['ip_address'])) {
|
||||
return $ipInfo['data']['value']['ip_address'];
|
||||
}
|
||||
}
|
||||
|
||||
Log::warning('No valid IP address found in vCenter response', [
|
||||
'vmware_id' => $this->moduleVmware->vmware_id,
|
||||
'ip_info' => $ipInfo
|
||||
]);
|
||||
return null;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error getting IP from vCenter', [
|
||||
'vmware_id' => $this->moduleVmware?->vmware_id ?? 'unknown',
|
||||
'error' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ReinstallLog extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'product_id',
|
||||
'product_type',
|
||||
'customer_id',
|
||||
'os_id',
|
||||
'template_id',
|
||||
'ip_address',
|
||||
'status',
|
||||
'error_message',
|
||||
'initiator',
|
||||
'note',
|
||||
];
|
||||
|
||||
public function customer()
|
||||
{
|
||||
return $this->belongsTo(Customer::class);
|
||||
}
|
||||
|
||||
public function os()
|
||||
{
|
||||
return $this->belongsTo(Os::class, 'os_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('reinstall_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
// Liên kết đến bảng sản phẩm (VPS/Hosting)
|
||||
$table->unsignedBigInteger('product_id');
|
||||
$table->unsignedTinyInteger('product_type'); // 3 = Hosting, 4 = VPS
|
||||
|
||||
// Liên kết tới user khởi tạo
|
||||
$table->unsignedBigInteger('custome_id')->nullable();
|
||||
|
||||
// Template & OS được sử dụng
|
||||
$table->unsignedBigInteger('os_id')->nullable(); // ID bảng operating_systems
|
||||
$table->string('template_id')->nullable(); // VMware Template ID
|
||||
|
||||
// IP hiện tại (nếu cần)
|
||||
$table->string('ip_address')->nullable();
|
||||
|
||||
// Trạng thái và kết quả
|
||||
$table->enum('status', ['pending', 'success', 'failed'])->default('pending');
|
||||
$table->text('error_message')->nullable();
|
||||
|
||||
// Metadata khác
|
||||
$table->string('initiator')->nullable(); // 'user', 'admin', 'system'
|
||||
$table->text('note')->nullable(); // Ghi chú tự do
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Index
|
||||
$table->index(['product_id', 'product_type']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('reinstall_logs');
|
||||
}
|
||||
};
|
||||
@@ -2,7 +2,7 @@
|
||||
@php
|
||||
$isWindows = Str::contains(Str::lower($vmInfo['os'] ?? ''), 'windows') ||
|
||||
Str::contains(Str::lower($invoice->invoiceItem->first()->os->osGroup->name ?? ''), 'windows');
|
||||
$vmIp = $vmInfo['ip'] ?? '103.42.56.177';
|
||||
$vmIp = $vmInfo['ip_address'] ?? '103.42.56.177';
|
||||
$vmPort = $isWindows ? '3389' : '22';
|
||||
$vmUser = $isWindows ? 'administrator' : 'root';
|
||||
$osName = $invoice->invoiceItem->first()->os->osGroup->name ?? 'Unknown';
|
||||
|
||||
@@ -29,67 +29,146 @@
|
||||
@if ($osGroups->count() > 0)
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Chọn loại hệ điều hành</label>
|
||||
<flux:select wire:model="selectedOsGroupId" placeholder="Chọn lại Hệ điều hành">
|
||||
<flux:select.option value="">Chọn lại hệ điều hành</flux:select.option>
|
||||
<label
|
||||
class="block text-sm font-medium text-gray-700 mb-2">{{ __('Chọn loại hệ điều hành') }}</label>
|
||||
<flux:select wire:model.live="selectedOsGroupId" placeholder="{{ __('Chọn loại hệ điều hành') }}"
|
||||
:disabled="$isLoading">
|
||||
<flux:select.option value="">{{ __('Chọn loại hệ điều hành') }}</flux:select.option>
|
||||
@foreach ($osGroups as $osGroup)
|
||||
<flux:select.option value="{{ $osGroup->id }}">{{ $osGroup->name }}</flux:select.option>
|
||||
<flux:select.option value="{{ $osGroup->id }}">{{ $osGroup->name }}
|
||||
</flux:select.option>
|
||||
@endforeach
|
||||
</flux:select>
|
||||
</div>
|
||||
|
||||
@if ($selectedOsGroupId && $operatingSystems->count() > 0)
|
||||
@if ($selectedOsGroupId)
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">{{ __('Chọn phiên bản:') }}</label>
|
||||
<div class="grid grid-cols-1 gap-3 max-h-60 overflow-y-auto">
|
||||
@foreach ($operatingSystems as $os)
|
||||
<label
|
||||
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<input type="radio" wire:model="selectedOsId" value="{{ $os->id }}"
|
||||
class="mr-3">
|
||||
<div class="flex-1">
|
||||
<div class="font-medium text-gray-900">{{ $os->osGroup->name . ' - ' . $os->version }}
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||
{{ __('Chọn phiên bản:') }}
|
||||
@if ($isLoading)
|
||||
<span class="text-sm text-gray-500 ml-2">
|
||||
<svg class="inline w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10"
|
||||
stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
||||
</path>
|
||||
</svg>
|
||||
{{ __('Đang tải...') }}
|
||||
</span>
|
||||
@endif
|
||||
</label>
|
||||
|
||||
@if ($isLoading)
|
||||
<div class="text-center py-8">
|
||||
<svg class="mx-auto h-8 w-8 text-gray-400 animate-spin" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10"
|
||||
stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
||||
</path>
|
||||
</svg>
|
||||
<p class="mt-2 text-sm text-gray-500">{{ __('Đang tải danh sách phiên bản...') }}</p>
|
||||
</div>
|
||||
@elseif ($operatingSystems->count() > 0)
|
||||
<div class="grid grid-cols-1 gap-3 max-h-60 overflow-y-auto">
|
||||
@foreach ($operatingSystems as $os)
|
||||
<label
|
||||
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 cursor-pointer transition-colors">
|
||||
<input type="radio" wire:model.live="selectedOsId" value="{{ $os->id }}"
|
||||
class="mr-3">
|
||||
<div class="flex-1">
|
||||
<div class="font-medium text-gray-900">
|
||||
{{ $os->osGroup->name . ' - ' . $os->version }}
|
||||
</div>
|
||||
@if ($os->description)
|
||||
<div class="text-sm text-gray-500 mt-1">
|
||||
{{ $os->description }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
@if ($currentOs && $currentOs->id == $os->id)
|
||||
<div class="flex items-center space-x-2">
|
||||
@if ($currentOs && $currentOs->id == $os->id)
|
||||
<span
|
||||
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
||||
{{ __('Hiện tại') }}
|
||||
</span>
|
||||
@endif
|
||||
<span
|
||||
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
||||
Hiện tại
|
||||
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
||||
{{ __('Khả dụng') }}
|
||||
</span>
|
||||
@endif
|
||||
<span
|
||||
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
||||
Khả dụng
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<div class="text-center py-8">
|
||||
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9.172 16.172a4 4 0 015.656 0M9 12h6m-6-4h6m2 5.291A7.962 7.962 0 0112 15c-2.34 0-4.47-.881-6.08-2.33" />
|
||||
</svg>
|
||||
<h3 class="mt-2 text-sm font-medium text-gray-900">{{ __('Không có phiên bản nào') }}
|
||||
</h3>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
{{ __('Không có phiên bản hệ điều hành nào khả dụng cho loại này.') }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@elseif($selectedOsGroupId)
|
||||
<div class="text-center py-8">
|
||||
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9.172 16.172a4 4 0 015.656 0M9 12h6m-6-4h6m2 5.291A7.962 7.962 0 0112 15c-2.34 0-4.47-.881-6.08-2.33" />
|
||||
</svg>
|
||||
<h3 class="mt-2 text-sm font-medium text-gray-900">{{ __('Không có phiên bản nào') }}</h3>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
{{ __('Không có phiên bản hệ điều hành nào khả dụng cho loại này.') }}</p>
|
||||
@endif
|
||||
|
||||
@if ($selectedOsId && $selectedOsDetails && $vpsInfo)
|
||||
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mt-4">
|
||||
<div class="flex items-start">
|
||||
<svg class="w-5 h-5 text-yellow-600 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
|
||||
</svg>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-sm font-medium text-yellow-800 mb-2">{{ __('Quý khách cài đặt lại VPS với thông tin như sau:') }}</h3>
|
||||
<div class="text-sm text-yellow-700 space-y-1">
|
||||
<p><strong>{{ __('VPS:') }}</strong> {{ $vpsIpAddress ?? $moduleVmware?->name ?? $vpsInfo->name ?? 'N/A' }}</p>
|
||||
<p><strong>{{ __('Hệ điều hành:') }}</strong> {{ $selectedOsDetails->osGroup->name ?? '' }} {{ $selectedOsDetails->version ?? '' }}</p>
|
||||
</div>
|
||||
<div class="mt-3 p-3 bg-yellow-100 rounded border border-yellow-300">
|
||||
<p class="text-sm text-yellow-800 font-medium">{{ __('Lưu ý:') }}</p>
|
||||
<p class="text-sm text-yellow-700">{{ __('Hành động này rất nguy hiểm, nó có thể xóa VPS và cài đặt lại. Quý khách vui lòng kiểm tra lại các VPS cần cài đặt lại.') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex justify-end space-x-3 pt-4 border-t border-gray-200">
|
||||
<flux:button variant="primary" x-on:click="$flux.modal('reinstall-vm').close()">
|
||||
<flux:button variant="primary" x-on:click="$flux.modal('reinstall-vm').close()" :disabled="$isLoading">
|
||||
{{ __('Hủy') }}
|
||||
</flux:button>
|
||||
<flux:button variant="primary" color="orange" wire:click="confirmReinstall">
|
||||
{{ __('Xác nhận cài lại') }}
|
||||
</flux:button>
|
||||
@if ($selectedOsId && $selectedOsDetails)
|
||||
<flux:button variant="primary" color="orange" wire:click="confirmReinstall" :disabled="$isLoading">
|
||||
@if ($isLoading)
|
||||
<svg class="w-4 h-4 mr-2 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
{{ __('Đang xử lý...') }}
|
||||
@else
|
||||
{{ __('Xác nhận cài lại') }}
|
||||
@endif
|
||||
</flux:button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="text-center py-8">
|
||||
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9.172 16.172a4 4 0 015.656 0M9 12h6m-6-4h6m2 5.291A7.962 7.962 0 0112 15c-2.34 0-4.47-.881-6.08-2.33" />
|
||||
</svg>
|
||||
<h3 class="mt-2 text-sm font-medium text-gray-900">{{ __('Không có hệ điều hành nào') }}</h3>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
{{ __('Không có hệ điều hành nào khả dụng cho VPS này.') }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</flux:modal>
|
||||
|
||||
@@ -518,6 +518,7 @@ Route::middleware("CustomerLoginCheck")->group(function () {
|
||||
Route::get('secure/get-snapshots', 'getSnapshots')->name('service.get.snapshots');
|
||||
Route::post('secure/remove-snapshot', 'removeSnapshot')->name('service.remove.snapshot');
|
||||
Route::post('secure/revert-snapshot', 'revertSnapshot')->name('service.revert.snapshot');
|
||||
Route::post('secure/reinstall-vm', 'reinstallVM')->name('service.reinstall.vm');
|
||||
Route::post('secure/start-vm', 'startVM')->name('service.start.vm');
|
||||
Route::post('secure/stop-vm', 'stopVM')->name('service.stop.vm');
|
||||
Route::post('secure/reboot-vm', 'rebootVM')->name('service.reboot.vm');
|
||||
|
||||
Reference in New Issue
Block a user