update sync vm
This commit is contained in:
@@ -1,38 +1,148 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\admin\vm;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Jobs\VirtualMachine\Sync\SyncVirtualMachine;
|
||||
use App\Repositories\Module\VirtualMachine\VirtualMachineRepositoryInterface;
|
||||
use App\Repositories\vCenter\vCenterRepositoryInterface;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
|
||||
class VirtualMachineController extends Controller
|
||||
{
|
||||
public function index()
|
||||
public function __construct(
|
||||
public VirtualMachineRepositoryInterface $virtualMachineRepository,
|
||||
public vCenterRepositoryInterface $vCenterRepository
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
return view('administrator.pages.package.vm.index');
|
||||
$vms = $this->virtualMachineRepository->filter(
|
||||
[
|
||||
'page' => $request->get('page') ?? 1
|
||||
]
|
||||
);
|
||||
$title = 'List all Virtual Machine';
|
||||
return view('administrator.pages.package.vm.index', compact('vms', 'title'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('administrator.pages.package.vm.add');
|
||||
$title = 'Add Virtual Machine';
|
||||
return view('administrator.pages.package.vm.add', compact('title'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
return view('administrator.pages.package.vm.index');
|
||||
$request->validate([
|
||||
'vm_id' => 'required|unique:virtual_machines,vm_id',
|
||||
'name' => 'required',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$data = $request->all();
|
||||
if (empty($data['uuid'])) {
|
||||
$data['uuid'] = Str::uuid();
|
||||
}
|
||||
$this->virtualMachineRepository->create($data);
|
||||
DB::commit();
|
||||
} catch (Exception $error) {
|
||||
DB::rollBack();
|
||||
return back()->withErrors($error->getMessage());
|
||||
}
|
||||
return redirect()->route('package.vm.index')->with('success', 'Add new VM successfully!');
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
return view('administrator.pages.package.vm.edit');
|
||||
$vm = $this->virtualMachineRepository->find($id);
|
||||
if (!$vm) {
|
||||
return back()->withErrors('Invalid request.');
|
||||
}
|
||||
$title = 'Edit Virtual Machine';
|
||||
return view('administrator.pages.package.vm.edit', compact('title', 'vm'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
return view('administrator.pages.package.vm.index');
|
||||
$vm = $this->virtualMachineRepository->find($id);
|
||||
if (!$vm) {
|
||||
return back()->withErrors('Invalid request.');
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'name' => 'required',
|
||||
'vm_id' => 'required|unique:virtual_machines,vm_id,' . $id,
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$this->virtualMachineRepository->update($id, $request->all());
|
||||
DB::commit();
|
||||
} catch (Exception $error) {
|
||||
DB::rollBack();
|
||||
return back()->withErrors($error->getMessage());
|
||||
}
|
||||
return redirect()->route('package.vm.index')->with('success', 'Update VM successfully!');
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
return view('administrator.pages.package.vm.index');
|
||||
$vm = $this->virtualMachineRepository->find($id);
|
||||
if (!$vm) {
|
||||
return back()->withErrors('Invalid request.');
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$this->virtualMachineRepository->delete($id);
|
||||
DB::commit();
|
||||
} catch (Exception $error) {
|
||||
DB::rollBack();
|
||||
return back()->withErrors($error->getMessage());
|
||||
}
|
||||
return redirect()->route('package.vm.index')->with('success', 'Deleted VM successfully!');
|
||||
}
|
||||
|
||||
public function sync(SyncVirtualMachine $syncVM)
|
||||
{
|
||||
dispatch($syncVM)->delay(now()->addSeconds(5));
|
||||
return back()->with('success', 'The process is being established, please wait');
|
||||
}
|
||||
|
||||
public function datatable(Request $request)
|
||||
{
|
||||
$query = $this->virtualMachineRepository->filter(
|
||||
$request->all(),
|
||||
['datacenter', 'host'],
|
||||
[],
|
||||
['*'],
|
||||
true
|
||||
);
|
||||
|
||||
return DataTables::eloquent($query)
|
||||
->addColumn(
|
||||
'action',
|
||||
function ($d) {
|
||||
return '<a href="' . route('package.vm.edit', $d->id) . '" class="btn btn-warning btn-sm"><i class="fas fa-search"></i></a>
|
||||
<form method="post" class="d-inline" action="' . route('package.vm.destroy', $d->id) . '">
|
||||
' . csrf_field() . '
|
||||
' . method_field('delete') . '
|
||||
<button type="submit" class="btn btn-sm btn-danger"><i class="fas fa-trash"></i></button>
|
||||
</form>';
|
||||
}
|
||||
)
|
||||
->editColumn('updated_at', function ($d) {
|
||||
return $d->updated_at ? $d->updated_at->format('H:i:s d/m/Y') : '';
|
||||
})
|
||||
->rawColumns(['action'])
|
||||
->make(true);
|
||||
}
|
||||
}
|
||||
@@ -77,6 +77,29 @@ class vCenter
|
||||
return "Login_Again";
|
||||
}
|
||||
|
||||
public function getAllVirtualMachine($datacenter = '')
|
||||
{
|
||||
$check = $this->checkApiExits();
|
||||
if ($check) {
|
||||
$params = [];
|
||||
if (!empty($datacenter)) {
|
||||
$params['filter.datacenters'] = $datacenter;
|
||||
}
|
||||
|
||||
$response = Http::withoutVerifying()
|
||||
->withHeaders([
|
||||
'vmware-api-session-id' => $this->token
|
||||
])
|
||||
->get("https://$this->apiUri/rest/vcenter/vm", $params)->json();
|
||||
|
||||
if (!isset($response['type'])) {
|
||||
return $response['value'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return "Login_Again";
|
||||
}
|
||||
|
||||
public function checkApiExits(): bool
|
||||
{
|
||||
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs\VirtualMachine\Sync;
|
||||
|
||||
use App\Http\Services\Telegram;
|
||||
use App\Http\Services\vCenter as ServiceVCenter;
|
||||
use App\Models\ModuleDatacenter;
|
||||
use App\Models\VirtualMachines;
|
||||
use App\Models\vCenter;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
use Throwable;
|
||||
|
||||
class SyncVirtualMachine implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected $vCenter;
|
||||
protected $telegram;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Keep constructor empty or minimal to ensure lightweight serialization
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->vCenter = new ServiceVCenter;
|
||||
$this->telegram = new Telegram();
|
||||
|
||||
try {
|
||||
$data = vCenter::select('id', 'host', 'user', 'password', 'token')->get();
|
||||
|
||||
$vCenterCount = 0;
|
||||
$vmTotalCount = 0;
|
||||
|
||||
foreach ($data as $item) {
|
||||
Log::info("Processing vCenter: {$item->host}");
|
||||
$this->vCenter->apiUri = $item->host;
|
||||
|
||||
// Always login to get a fresh token
|
||||
$token = $this->vCenter->loginServer($item);
|
||||
if ($token) {
|
||||
$item->token = $token;
|
||||
$item->save();
|
||||
$this->vCenter->token = $token;
|
||||
} else {
|
||||
$this->vCenter->token = null;
|
||||
Log::error("Login failed for {$item->host}");
|
||||
}
|
||||
|
||||
if (!$this->vCenter->token) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$datacenters = ModuleDatacenter::where('vcenter_id', $item->id)->get();
|
||||
if ($datacenters->count() > 0) {
|
||||
foreach ($datacenters as $dc) {
|
||||
$vms = $this->vCenter->getAllVirtualMachine($dc->datacenter_id);
|
||||
$vmCount = $this->processVMs($vms, $item, $dc->id); // Extract method for reuse
|
||||
$vmTotalCount += $vmCount;
|
||||
}
|
||||
} else {
|
||||
// Fallback: Sync all VMs without datacenter context
|
||||
Log::info("No datacenters found, fetching all VMs for {$item->host}");
|
||||
$vms = $this->vCenter->getAllVirtualMachine();
|
||||
$vmCount = $this->processVMs($vms, $item, null);
|
||||
$vmTotalCount += $vmCount;
|
||||
}
|
||||
|
||||
$vCenterCount++; // Increment vCenter synced count
|
||||
}
|
||||
|
||||
// Notify success via Telegram
|
||||
$this->telegram->SendJobRunInfo('SyncVirtualMachine', 'Success', [
|
||||
'message' => 'Sync VMs completed successfully',
|
||||
'synced_vcenter_count' => $vCenterCount,
|
||||
'synced_vm_count' => $vmTotalCount,
|
||||
]);
|
||||
|
||||
} catch (Throwable $e) {
|
||||
Log::error("SyncVirtualMachine Job Failed: " . $e->getMessage());
|
||||
// Gửi log lỗi qua Telegram
|
||||
if (isset($this->telegram)) {
|
||||
$this->telegram->SendJobRunInfo('SyncVirtualMachine', 'Failed', [
|
||||
'error' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function processVMs($vms, $vCenterItem, $datacenterId)
|
||||
{
|
||||
// If token expired, retry login (handled inside loop in previous logic, but simpler here if we just handle the array check)
|
||||
if ($vms === 'Login_Again') {
|
||||
Log::info("Token expired, retrying login for {$vCenterItem->host}");
|
||||
$token = $this->vCenter->loginServer($vCenterItem);
|
||||
if ($token) {
|
||||
$vCenterItem->token = $token;
|
||||
$vCenterItem->save();
|
||||
$this->vCenter->token = $token;
|
||||
// Retry fetch
|
||||
$vms = $this->vCenter->getAllVirtualMachine($datacenterId ? ModuleDatacenter::find($datacenterId)->datacenter_id : '');
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_array($vms)) {
|
||||
Log::warning("Failed to fetch VMs or empty response. Response: " . json_encode($vms));
|
||||
return 0;
|
||||
}
|
||||
|
||||
Log::info("Fetched " . count($vms) . " VMs");
|
||||
$count = 0;
|
||||
foreach ($vms as $vmData) {
|
||||
$vmObj = VirtualMachines::firstOrNew(['vm_id' => $vmData['vm']]);
|
||||
|
||||
if (!$vmObj->exists) {
|
||||
$vmObj->uuid = Str::uuid();
|
||||
}
|
||||
|
||||
$vmObj->name = $vmData['name'];
|
||||
$vmObj->power_state = $vmData['power_state'];
|
||||
$vmObj->cpu = $vmData['cpu_count'] ?? 0;
|
||||
$vmObj->ram_mb = $vmData['memory_size_MiB'] ?? 0;
|
||||
$vmObj->datacenter_id = $datacenterId; // Assign datacenter if known
|
||||
$vmObj->last_synced_at = now();
|
||||
|
||||
$vmObj->save();
|
||||
$count++;
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,29 @@ use Illuminate\Database\Eloquent\Model;
|
||||
class VirtualMachines extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'uuid',
|
||||
'vm_id',
|
||||
'name',
|
||||
'power_state',
|
||||
'folder',
|
||||
'is_template',
|
||||
'cpu',
|
||||
'ram_mb',
|
||||
'is_system',
|
||||
'last_synced_at',
|
||||
'datacenter_id',
|
||||
'host_id'
|
||||
];
|
||||
|
||||
public function datacenter()
|
||||
{
|
||||
return $this->belongsTo(ModuleDatacenter::class, 'datacenter_id');
|
||||
}
|
||||
|
||||
public function host()
|
||||
{
|
||||
return $this->belongsTo(ModuleHost::class, 'host_id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,8 @@ use App\Repositories\vCenter\vCenterCachedRepository;
|
||||
use App\Repositories\vCenter\vCenterRepositoryInterface;
|
||||
use App\Repositories\VPS\VPSCachedRepository;
|
||||
use App\Repositories\VPS\VPSRepositoryInterface;
|
||||
use App\Repositories\Module\VirtualMachine\VirtualMachineRepository;
|
||||
use App\Repositories\Module\VirtualMachine\VirtualMachineRepositoryInterface;
|
||||
|
||||
class RepositoryProvider extends ServiceProvider
|
||||
{
|
||||
@@ -335,6 +337,12 @@ class RepositoryProvider extends ServiceProvider
|
||||
IPPoolRepositoryInterface::class,
|
||||
IPPoolCachedRepository::class
|
||||
);
|
||||
|
||||
//Module VirtualMachine
|
||||
$this->app->bind(
|
||||
VirtualMachineRepositoryInterface::class,
|
||||
VirtualMachineRepository::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories\Module\VirtualMachine;
|
||||
|
||||
use App\Models\VirtualMachines;
|
||||
use App\Repositories\BaseRepository;
|
||||
|
||||
class VirtualMachineRepository extends BaseRepository implements VirtualMachineRepositoryInterface
|
||||
{
|
||||
public function getModel()
|
||||
{
|
||||
return VirtualMachines::class;
|
||||
}
|
||||
|
||||
public function filter(
|
||||
array $data = [],
|
||||
array $relationships = [],
|
||||
array $withCount = [],
|
||||
array $select = ['*'],
|
||||
bool $returnQuery = false
|
||||
) {
|
||||
$query = $this->model
|
||||
->select($select)
|
||||
->with($relationships);
|
||||
|
||||
if (!empty($data['datacenter_id'])) {
|
||||
$query->where('datacenter_id', $data['datacenter_id']);
|
||||
}
|
||||
|
||||
if (!empty($data['host_id'])) {
|
||||
$query->where('host_id', $data['host_id']);
|
||||
}
|
||||
|
||||
if (!empty($data['name'])) {
|
||||
$query->where('name', 'like', '%' . $data['name'] . '%');
|
||||
}
|
||||
|
||||
if (!empty($withCount)) {
|
||||
$query->withCount($withCount);
|
||||
}
|
||||
|
||||
if ($returnQuery) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
if (!empty($data['paginate']) || !empty($data['page'])) {
|
||||
return $query->paginate(
|
||||
$data['per_page'] ?? 15
|
||||
);
|
||||
}
|
||||
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
public function findBy(string $key = '', string|int|null $value = '')
|
||||
{
|
||||
if (empty($key) || empty($value)) {
|
||||
return false;
|
||||
}
|
||||
return $this->model->where($key, $value)->first();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories\Module\VirtualMachine;
|
||||
|
||||
use App\Repositories\BaseRepositoryInterface;
|
||||
|
||||
interface VirtualMachineRepositoryInterface extends BaseRepositoryInterface {
|
||||
public function filter(
|
||||
array $data = [],
|
||||
array $relationships = [],
|
||||
array $withCount = [],
|
||||
array $select = ['*'],
|
||||
bool $returnQuery = false
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user