mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-13 14:15:58 +00:00
feat(v5): add server reconciliation and canvas APIs
Split V5 dashboard behavior into domain controllers and policies, add agent token rotation/revocation, status reconciliation jobs, ingress firewall syncing, and canvas connection APIs. Add migrations for V5 status tracking, server capabilities, resource connection aliases, and revoked agent tokens.
This commit is contained in:
1 parent
df854feee8
commit
6ae45684f9
147 files changed
+22444
-10407
No files matched your search
@@ -0,0 +1,48 @@
|
||||
<?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('v5_servers', function (Blueprint $table) {
|
||||
$table->index('wireguard_management_ip');
|
||||
$table->index('node_address');
|
||||
$table->index('host');
|
||||
});
|
||||
|
||||
Schema::table('v5_applications', function (Blueprint $table) {
|
||||
$table->index('runtime_container_id');
|
||||
});
|
||||
|
||||
Schema::table('v5_container_statuses', function (Blueprint $table) {
|
||||
$table->index('last_seen_at');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->dropIndex(['wireguard_management_ip']);
|
||||
$table->dropIndex(['node_address']);
|
||||
$table->dropIndex(['host']);
|
||||
});
|
||||
|
||||
Schema::table('v5_applications', function (Blueprint $table) {
|
||||
$table->dropIndex(['runtime_container_id']);
|
||||
});
|
||||
|
||||
Schema::table('v5_container_statuses', function (Blueprint $table) {
|
||||
$table->dropIndex(['last_seen_at']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
DB::table('v5_servers')
|
||||
->whereNull('uuid')
|
||||
->pluck('id')
|
||||
->each(function (int $id): void {
|
||||
DB::table('v5_servers')
|
||||
->where('id', $id)
|
||||
->update(['uuid' => Str::lower(Str::random(24))]);
|
||||
});
|
||||
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->string('uuid')->nullable(false)->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->string('uuid')->nullable()->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
<?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('v5_servers', function (Blueprint $table) {
|
||||
$table->timestamp('status_observed_at')->nullable()->after('status');
|
||||
});
|
||||
|
||||
Schema::table('v5_applications', function (Blueprint $table) {
|
||||
$table->timestamp('status_observed_at')->nullable()->after('status_message');
|
||||
});
|
||||
|
||||
Schema::table('v5_container_statuses', function (Blueprint $table) {
|
||||
$table->timestamp('status_observed_at')->nullable()->after('status_message');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->dropColumn('status_observed_at');
|
||||
});
|
||||
|
||||
Schema::table('v5_applications', function (Blueprint $table) {
|
||||
$table->dropColumn('status_observed_at');
|
||||
});
|
||||
|
||||
Schema::table('v5_container_statuses', function (Blueprint $table) {
|
||||
$table->dropColumn('status_observed_at');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -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
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->string('coold_version')->nullable()->after('wireguard_public_key');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->dropColumn('coold_version');
|
||||
});
|
||||
}
|
||||
};
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Rewrites v5 polymorphic rows that stored the Application FQCN (written
|
||||
* before the 'v5.application' morph alias existed) so a future class rename
|
||||
* cannot orphan them. New rows pick up the alias via getMorphClass().
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
private const FQCN = 'App\Models\V5\Application';
|
||||
|
||||
private const ALIAS = 'v5.application';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$this->rewriteMorphTypes(self::FQCN, self::ALIAS);
|
||||
$this->rewritePairKeys(self::FQCN, self::ALIAS);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->rewriteMorphTypes(self::ALIAS, self::FQCN);
|
||||
$this->rewritePairKeys(self::ALIAS, self::FQCN);
|
||||
}
|
||||
|
||||
private function rewriteMorphTypes(string $from, string $to): void
|
||||
{
|
||||
if (Schema::hasTable('v5_resource_connections')) {
|
||||
foreach (['resource_one_type', 'resource_two_type'] as $column) {
|
||||
DB::table('v5_resource_connections')
|
||||
->where($column, $from)
|
||||
->update([$column => $to]);
|
||||
}
|
||||
}
|
||||
|
||||
if (Schema::hasTable('v5_resource_connection_rules')) {
|
||||
foreach (['source_resource_type', 'target_resource_type'] as $column) {
|
||||
DB::table('v5_resource_connection_rules')
|
||||
->where($column, $from)
|
||||
->update([$column => $to]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function rewritePairKeys(string $from, string $to): void
|
||||
{
|
||||
if (! Schema::hasTable('v5_resource_connections')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Backslash escaping in LIKE patterns differs between Postgres and
|
||||
// SQLite, so match the FQCN in PHP instead of in SQL.
|
||||
DB::table('v5_resource_connections')
|
||||
->select(['id', 'resource_pair_key'])
|
||||
->orderBy('id')
|
||||
->chunkById(100, function ($connections) use ($from, $to): void {
|
||||
foreach ($connections as $connection) {
|
||||
if (! str_contains((string) $connection->resource_pair_key, $from)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('v5_resource_connections')
|
||||
->where('id', $connection->id)
|
||||
->update([
|
||||
'resource_pair_key' => str_replace($from, $to, $connection->resource_pair_key),
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Replaces the unindexable v5_servers.capabilities JSON array of magic strings
|
||||
* with indexed has_coold / is_ingress booleans. The Server model keeps
|
||||
* exposing a computed `capabilities` array so serialized payloads stay
|
||||
* identical.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->boolean('has_coold')->default(false)->index();
|
||||
$table->boolean('is_ingress')->default(false)->index();
|
||||
});
|
||||
|
||||
DB::table('v5_servers')
|
||||
->select(['id', 'capabilities'])
|
||||
->orderBy('id')
|
||||
->chunkById(100, function ($servers): void {
|
||||
foreach ($servers as $server) {
|
||||
$capabilities = json_decode($server->capabilities ?? '[]', true);
|
||||
|
||||
if (! is_array($capabilities) || $capabilities === []) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('v5_servers')->where('id', $server->id)->update([
|
||||
'has_coold' => in_array('coold', $capabilities, true),
|
||||
'is_ingress' => in_array('ingress', $capabilities, true),
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->dropColumn('capabilities');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->json('capabilities')->nullable();
|
||||
});
|
||||
|
||||
DB::table('v5_servers')
|
||||
->select(['id', 'has_coold', 'is_ingress'])
|
||||
->orderBy('id')
|
||||
->chunkById(100, function ($servers): void {
|
||||
foreach ($servers as $server) {
|
||||
$capabilities = array_values(array_filter([
|
||||
$server->has_coold ? 'coold' : null,
|
||||
$server->is_ingress ? 'ingress' : null,
|
||||
]));
|
||||
|
||||
DB::table('v5_servers')->where('id', $server->id)->update([
|
||||
'capabilities' => json_encode($capabilities),
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->dropIndex(['has_coold']);
|
||||
$table->dropIndex(['is_ingress']);
|
||||
$table->dropColumn(['has_coold', 'is_ingress']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<?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('v5_servers', function (Blueprint $table) {
|
||||
$table->string('agent_token_jti')->nullable()->after('coold_version');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->dropColumn('agent_token_jti');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
<?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::create('v5_revoked_agent_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('jti')->unique();
|
||||
$table->foreignId('server_id')->nullable();
|
||||
$table->timestamp('revoked_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable()->index();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('v5_revoked_agent_tokens');
|
||||
}
|
||||
};
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?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('v5_servers', function (Blueprint $table) {
|
||||
$table->timestamp('agent_token_expires_at')->nullable()->after('agent_token_jti');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('v5_servers', function (Blueprint $table) {
|
||||
$table->dropColumn('agent_token_expires_at');
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user