'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; } }