142 lines
5.0 KiB
PHP
142 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace App\Jobs\VirtualMachine\Action;
|
|
|
|
use App\Http\Services\vCenter;
|
|
use App\Mail\ChangePortRemote;
|
|
use App\Models\ModuleVmware;
|
|
use Illuminate\Bus\Queueable;
|
|
use Illuminate\Contracts\Encryption\DecryptException;
|
|
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\Facades\Mail;
|
|
use Str;
|
|
|
|
class ChangeRemotePortJob implements ShouldQueue
|
|
{
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
|
|
public int $tries = 3;
|
|
public int $timeout = 180;
|
|
|
|
public function __construct(
|
|
public string $productId,
|
|
public string $newPort,
|
|
public string $password,
|
|
public int $userId,
|
|
public string $email
|
|
) {
|
|
}
|
|
|
|
public function handle(vCenter $serviceVCenter): void
|
|
{
|
|
$product = ModuleVmware::with('ipAddress.host.datacenter.vCenter', 'os.osGroup')
|
|
->where('vmware_id', $this->productId)
|
|
->where('customer_id', $this->userId)
|
|
->firstOrFail();
|
|
|
|
$osFamily = (string) ($product->os->osGroup->name ?? '');
|
|
$isWindows = stripos($osFamily, 'windows') !== false;
|
|
if (!$isWindows) {
|
|
throw new \RuntimeException('Only Windows is supported by this reset job.');
|
|
}
|
|
|
|
$vmName = $product->ipAddress->vm_name
|
|
?? $product->name
|
|
?? $product->hostname
|
|
?? null;
|
|
|
|
if (!$vmName && preg_match('/^vm-\d+$/i', (string) $product->vmware_id)) {
|
|
$rawName = trim($serviceVCenter->runPsCommand("(Get-VM -Id '" . addslashes($product->vmware_id) . "').Name"));
|
|
if (($p = strpos($rawName, '[STDERR]')) !== false) {
|
|
$rawName = trim(substr($rawName, 0, $p));
|
|
}
|
|
$vmName = trim(preg_replace('/\s+/', ' ', $rawName));
|
|
}
|
|
if (!$vmName) {
|
|
throw new \RuntimeException('Cannot resolve VM Name on vCenter.');
|
|
}
|
|
|
|
$guestUser = 'Administrator';
|
|
|
|
$result = $serviceVCenter->changeRDPPortWindows(
|
|
vmName: $vmName,
|
|
guestUser: 'Administrator',
|
|
guestPassword: $this->password,
|
|
newPort: $this->newPort,
|
|
);
|
|
|
|
if ($result === 'Login_Fail' || $result === false || $result === null) {
|
|
throw new \RuntimeException('SSH runner login failed.');
|
|
}
|
|
if (is_string($result)) {
|
|
// Script trả non-JSON → bắn lỗi kèm raw để debug
|
|
throw new \RuntimeException('Script returned non-JSON output: ' . $result);
|
|
}
|
|
|
|
/**
|
|
* Chuẩn hoá $row:
|
|
* - Script 1-VM: trả 1 object: ['vm'=>.., 'status'=>.., 'message'=>.., 'newPort'=>..]
|
|
* - (Phòng hờ) Nếu lỡ trả array nhiều item, chọn item có 'vm' trùng $vmName, không thì lấy phần tử đầu.
|
|
*/
|
|
$row = null;
|
|
|
|
if (is_array($result)) {
|
|
// case: object đơn
|
|
if (isset($result['vm']) && isset($result['status'])) {
|
|
$row = $result;
|
|
} else {
|
|
// case: mảng các object
|
|
// Tìm theo vmName
|
|
foreach ($result as $it) {
|
|
if (is_array($it) && (($it['vm'] ?? null) === $vmName)) {
|
|
$row = $it;
|
|
break;
|
|
}
|
|
}
|
|
// fallback: phần tử đầu tiên nếu chưa có
|
|
if ($row === null && isset($result[0]) && is_array($result[0])) {
|
|
$row = $result[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!is_array($row) || empty($row)) {
|
|
Log::error('ChangeRemotePortJob: invalid script response shape', ['vm' => $vmName, 'raw' => $result]);
|
|
throw new \RuntimeException('Invalid script response.');
|
|
}
|
|
|
|
// Đọc trường returned
|
|
$status = strtolower((string) ($row['status'] ?? ''));
|
|
$message = (string) ($row['message'] ?? '');
|
|
$newPort = (string) ($row['newPort'] ?? $this->newPort);
|
|
|
|
// Xét thành công: status === 'ok'
|
|
$ok = ($status === 'ok');
|
|
|
|
Log::info('ChangeRemotePortJob: script result', [
|
|
'vm' => $vmName,
|
|
'status' => $status,
|
|
'message' => $message,
|
|
'newPort' => $newPort,
|
|
'raw' => $row,
|
|
]);
|
|
|
|
if (!$ok) {
|
|
// Nếu muốn cho phép 'warning' pass, có thể đổi điều kiện ở trên hoặc thêm nhánh dưới:
|
|
// if ($status === 'warning' && str_contains(strtolower($message), 'rdp port is now')) { $ok = true; }
|
|
throw new \RuntimeException($message !== '' ? $message : ('Change RDP port failed with status: ' . $status));
|
|
}
|
|
|
|
// Gửi mail thông báo
|
|
Mail::to($this->email)->send(
|
|
new ChangePortRemote(vmName: $vmName, newPort: (string) $newPort)
|
|
);
|
|
|
|
Log::info('ChangeRemotePortJob: success', ['vm' => $vmName, 'newPort' => $newPort]);
|
|
}
|
|
}
|