Refactor VM provisioning pipeline into focused services and add IP pool
management
This commit is contained in:
@@ -12,10 +12,23 @@ return new class extends Migration {
|
||||
{
|
||||
Schema::create('ip_pools', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->uuid('uuid')->unique();
|
||||
|
||||
$table->string('ip_address');
|
||||
|
||||
$table->unsignedBigInteger('module_network_id');
|
||||
$table->foreign('module_network_id')->references('id')->on('module_network');
|
||||
|
||||
$table->enum('status', ['free', 'assigned', 'reserved'])->default('free');
|
||||
|
||||
$table->unsignedBigInteger('service_id')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['module_network_id', 'status']);
|
||||
$table->index('service_id');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
if (!Schema::hasColumn('products', 'thumbnail')) {
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->string('thumbnail')->nullable()->after('description');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// The base create_products migration already defines this nullable column.
|
||||
// Keep rollback as a no-op so rolling back this compatibility migration
|
||||
// cannot remove an existing column from fresh databases.
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('ip_pools', function (Blueprint $table) {
|
||||
$table->uuid('uuid')->nullable()->unique()->after('id');
|
||||
});
|
||||
|
||||
// Backfill existing rows
|
||||
DB::table('ip_pools')->whereNull('uuid')->orderBy('id')->each(function ($row) {
|
||||
DB::table('ip_pools')->where('id', $row->id)->update(['uuid' => (string) Str::uuid()]);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('ip_pools', function (Blueprint $table) {
|
||||
$table->dropColumn('uuid');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('virtual_machines', function (Blueprint $table) {
|
||||
$table->unsignedBigInteger('ip_pool_id')->nullable()->after('host_id');
|
||||
$table->string('ip', 45)->nullable()->after('ip_pool_id');
|
||||
|
||||
$table->foreign('ip_pool_id')
|
||||
->references('id')
|
||||
->on('ip_pools')
|
||||
->nullOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('virtual_machines', function (Blueprint $table) {
|
||||
$table->dropForeign(['ip_pool_id']);
|
||||
$table->dropColumn(['ip_pool_id', 'ip']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('ip_pools', function (Blueprint $table) {
|
||||
$table->string('gateway')->nullable()->after('ip_address');
|
||||
$table->unsignedTinyInteger('cidr')->default(24)->after('gateway');
|
||||
|
||||
$table
|
||||
->enum('status', ['free', 'assigned', 'reserved'])
|
||||
->default('free')
|
||||
->after('module_network_id');
|
||||
|
||||
$table->foreignId('service_id')->nullable()->after('status')->constrained('services')->nullOnDelete();
|
||||
|
||||
$table->index(['status', 'module_network_id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('ip_pools', function (Blueprint $table) {
|
||||
$table->dropForeign(['service_id']);
|
||||
$table->dropIndex(['status', 'module_network_id']);
|
||||
|
||||
$table->dropColumn(['gateway', 'cidr', 'status', 'service_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -15,7 +15,7 @@ use Illuminate\Support\Facades\Log;
|
||||
* Cách cấu hình pools() bên dưới:
|
||||
*
|
||||
* // Theo CIDR:
|
||||
* ['network' => 'LAN-VPS-01', 'cidr' => '103.90.224.0/26']
|
||||
* ['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']
|
||||
@@ -26,7 +26,7 @@ use Illuminate\Support\Facades\Log;
|
||||
* // 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) và IP cuối (broadcast) trong CIDR tự động bị loại bỏ.
|
||||
* 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
|
||||
@@ -42,7 +42,8 @@ class IpPoolSeeder extends Seeder
|
||||
// --- 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 = 62 usable IPs (.1 → .62)
|
||||
'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 ---
|
||||
@@ -91,6 +92,10 @@ class IpPoolSeeder extends Seeder
|
||||
[
|
||||
'ip_address' => $ip,
|
||||
'module_network_id' => $network->id,
|
||||
],
|
||||
[
|
||||
'gateway' => $pool['gateway'] ?? null,
|
||||
'cidr' => $this->resolveCidr($pool),
|
||||
]
|
||||
);
|
||||
|
||||
@@ -130,20 +135,53 @@ class IpPoolSeeder extends Seeder
|
||||
private function generateIps(array $pool): array
|
||||
{
|
||||
if (!empty($pool['ips'])) {
|
||||
return array_values(array_filter($pool['ips'], fn($ip) => filter_var($ip, FILTER_VALIDATE_IP)));
|
||||
return $this->withoutGateway(
|
||||
array_values(array_filter($pool['ips'], fn($ip) => filter_var($ip, FILTER_VALIDATE_IP))),
|
||||
$pool
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($pool['cidr'])) {
|
||||
return $this->ipsFromCidr($pool['cidr']);
|
||||
return $this->withoutGateway($this->ipsFromCidr($pool['cidr']), $pool);
|
||||
}
|
||||
|
||||
if (!empty($pool['start']) && !empty($pool['end'])) {
|
||||
return $this->ipsFromRange($pool['start'], $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
|
||||
|
||||
Reference in New Issue
Block a user