Files
portal-api/database/seeders/IpPoolSeeder.php
T

228 lines
6.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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;
}
}