228 lines
6.8 KiB
PHP
228 lines
6.8 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace Database\Seeders;
|
||
|
||
use App\Models\IpPool;
|
||
use App\Models\ModuleNetwork;
|
||
use Illuminate\Database\Seeder;
|
||
use Illuminate\Support\Facades\Log;
|
||
|
||
/**
|
||
* IpPoolSeeder — nhập danh sách IP vào ip_pools để assign cho VM khi khởi tạo dịch vụ.
|
||
*
|
||
* Cách cấu hình pools() bên dưới:
|
||
*
|
||
* // Theo CIDR:
|
||
* ['network' => 'LAN-VPS-01', 'cidr' => '103.90.224.0/26', 'gateway' => '103.90.224.1']
|
||
*
|
||
* // Theo range:
|
||
* ['network' => 'LAN-VPS-01', 'start' => '103.90.224.10', 'end' => '103.90.224.60']
|
||
*
|
||
* // Danh sách IP thủ công:
|
||
* ['network' => 'LAN-VPS-01', 'ips' => ['103.90.224.10', '103.90.224.11', ...]]
|
||
*
|
||
* // Có thể dùng module_network_id thay vì tên network:
|
||
* ['network_id' => 1, 'cidr' => '103.90.224.0/26']
|
||
*
|
||
* IP đầu (network address), IP cuối (broadcast), và gateway trong CIDR tự động bị loại bỏ.
|
||
* Khi VM được tạo, hệ thống sẽ lấy IP đầu tiên chưa được assign trong module_ip_address.
|
||
*/
|
||
class IpPoolSeeder extends Seeder
|
||
{
|
||
/**
|
||
* ============================================================
|
||
* ĐỊA CHỈ IP POOLS — CHỈNH SỬA TẠI ĐÂY
|
||
* ============================================================
|
||
*/
|
||
private function pools(): array
|
||
{
|
||
return [
|
||
// --- Pool 1: VPS Public Network (module_network id=1, name="VM Network") ---
|
||
[
|
||
'network_id' => 1, // module_network.id
|
||
'cidr' => '103.90.224.0/26', // /26, gateway .1, cấp phát .2 → .62
|
||
'gateway' => '103.90.224.1',
|
||
],
|
||
|
||
// --- Pool 2: thêm range thủ công ---
|
||
// [
|
||
// 'network' => 'LAN-VPS-02',
|
||
// 'start' => '10.10.20.50',
|
||
// 'end' => '10.10.20.100',
|
||
// ],
|
||
|
||
// --- Pool 3: danh sách IP cụ thể ---
|
||
// [
|
||
// 'network_id' => 2,
|
||
// 'ips' => [
|
||
// '192.168.100.10',
|
||
// '192.168.100.11',
|
||
// '192.168.100.12',
|
||
// ],
|
||
// ],
|
||
];
|
||
}
|
||
|
||
// ============================================================
|
||
|
||
public function run(): void
|
||
{
|
||
$totalInserted = 0;
|
||
$totalSkipped = 0;
|
||
|
||
foreach ($this->pools() as $pool) {
|
||
$network = $this->resolveNetwork($pool);
|
||
|
||
if (!$network) {
|
||
$this->command->warn('IpPoolSeeder: không tìm thấy network: ' . json_encode($pool));
|
||
continue;
|
||
}
|
||
|
||
$ips = $this->generateIps($pool);
|
||
|
||
if (empty($ips)) {
|
||
$this->command->warn("IpPoolSeeder: không có IP nào được generate cho network #{$network->id}");
|
||
continue;
|
||
}
|
||
|
||
foreach ($ips as $ip) {
|
||
$created = IpPool::updateOrCreate(
|
||
[
|
||
'ip_address' => $ip,
|
||
'module_network_id' => $network->id,
|
||
],
|
||
[
|
||
'gateway' => $pool['gateway'] ?? null,
|
||
'cidr' => $this->resolveCidr($pool),
|
||
]
|
||
);
|
||
|
||
if ($created->wasRecentlyCreated) {
|
||
$totalInserted++;
|
||
} else {
|
||
$totalSkipped++;
|
||
}
|
||
}
|
||
|
||
$this->command->info("✅ Network [{$network->name}] (id={$network->id}): " . count($ips) . " IPs xử lý xong.");
|
||
}
|
||
|
||
$this->command->info("IpPoolSeeder hoàn tất: {$totalInserted} IPs mới, {$totalSkipped} IPs đã tồn tại.");
|
||
}
|
||
|
||
// -------------------------------------------------------------------------
|
||
|
||
private function resolveNetwork(array $pool): ?ModuleNetwork
|
||
{
|
||
if (!empty($pool['network_id'])) {
|
||
return ModuleNetwork::find($pool['network_id']);
|
||
}
|
||
|
||
if (!empty($pool['network'])) {
|
||
return ModuleNetwork::where('name', $pool['network'])->first();
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Generate danh sách IP từ CIDR, range start–end, hoặc mảng IP thủ công.
|
||
*
|
||
* @return string[]
|
||
*/
|
||
private function generateIps(array $pool): array
|
||
{
|
||
if (!empty($pool['ips'])) {
|
||
return $this->withoutGateway(
|
||
array_values(array_filter($pool['ips'], fn($ip) => filter_var($ip, FILTER_VALIDATE_IP))),
|
||
$pool
|
||
);
|
||
}
|
||
|
||
if (!empty($pool['cidr'])) {
|
||
return $this->withoutGateway($this->ipsFromCidr($pool['cidr']), $pool);
|
||
}
|
||
|
||
if (!empty($pool['start']) && !empty($pool['end'])) {
|
||
return $this->withoutGateway($this->ipsFromRange($pool['start'], $pool['end']), $pool);
|
||
}
|
||
|
||
return [];
|
||
}
|
||
|
||
private function resolveCidr(array $pool): int
|
||
{
|
||
if (!empty($pool['prefix'])) {
|
||
return (int) $pool['prefix'];
|
||
}
|
||
|
||
if (!empty($pool['cidr']) && str_contains($pool['cidr'], '/')) {
|
||
return (int) explode('/', $pool['cidr'])[1];
|
||
}
|
||
|
||
return 24;
|
||
}
|
||
|
||
/**
|
||
* Không đưa gateway vào IP pool để tránh cấp gateway cho VM.
|
||
*
|
||
* @param string[] $ips
|
||
* @return string[]
|
||
*/
|
||
private function withoutGateway(array $ips, array $pool): array
|
||
{
|
||
$gateway = $pool['gateway'] ?? null;
|
||
|
||
if (!$gateway || !filter_var($gateway, FILTER_VALIDATE_IP)) {
|
||
return $ips;
|
||
}
|
||
|
||
return array_values(array_filter($ips, fn(string $ip): bool => $ip !== $gateway));
|
||
}
|
||
|
||
/**
|
||
* Lấy tất cả usable IPs từ CIDR (bỏ network address và broadcast).
|
||
* Ví dụ: 103.90.224.0/26 → .1 đến .62
|
||
*/
|
||
private function ipsFromCidr(string $cidr): array
|
||
{
|
||
[$baseIp, $prefix] = explode('/', $cidr);
|
||
|
||
$prefix = (int) $prefix;
|
||
$baseInt = ip2long($baseIp);
|
||
$mask = ~((1 << (32 - $prefix)) - 1);
|
||
$network = $baseInt & $mask;
|
||
$broadcast = $network | ~$mask;
|
||
|
||
$ips = [];
|
||
// Bỏ qua network address (.0) và broadcast (.255 hoặc cuối range)
|
||
for ($i = $network + 1; $i < $broadcast; $i++) {
|
||
$ips[] = long2ip($i);
|
||
}
|
||
|
||
return $ips;
|
||
}
|
||
|
||
/**
|
||
* Lấy tất cả IPs trong range start → end (inclusive).
|
||
*/
|
||
private function ipsFromRange(string $start, string $end): array
|
||
{
|
||
$startInt = ip2long($start);
|
||
$endInt = ip2long($end);
|
||
|
||
if ($startInt === false || $endInt === false || $startInt > $endInt) {
|
||
return [];
|
||
}
|
||
|
||
$ips = [];
|
||
for ($i = $startInt; $i <= $endInt; $i++) {
|
||
$ips[] = long2ip($i);
|
||
}
|
||
|
||
return $ips;
|
||
}
|
||
}
|