Implement Keystone environment deployments
This commit is contained in:
29
database/factories/ApplicationFactory.php
Normal file
29
database/factories/ApplicationFactory.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\RepositoryType;
|
||||
use App\Models\Organisation;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Application>
|
||||
*/
|
||||
class ApplicationFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'organisation_id' => Organisation::factory(),
|
||||
'name' => $this->faker->words(2, true),
|
||||
'repository_url' => 'git@example.com:org/'.$this->faker->slug().'.git',
|
||||
'repository_type' => RepositoryType::GIT,
|
||||
'default_branch' => 'main',
|
||||
];
|
||||
}
|
||||
}
|
||||
31
database/factories/EnvironmentFactory.php
Normal file
31
database/factories/EnvironmentFactory.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\SchedulerMode;
|
||||
use App\Models\Application;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Environment>
|
||||
*/
|
||||
class EnvironmentFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'application_id' => Application::factory(),
|
||||
'name' => 'production',
|
||||
'branch' => 'main',
|
||||
'status' => 'active',
|
||||
'scheduler_enabled' => true,
|
||||
'scheduler_mode' => SchedulerMode::SINGLE,
|
||||
'build_config' => [],
|
||||
];
|
||||
}
|
||||
}
|
||||
29
database/factories/OperationFactory.php
Normal file
29
database/factories/OperationFactory.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\OperationKind;
|
||||
use App\Enums\OperationStatus;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Operation>
|
||||
*/
|
||||
class OperationFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'kind' => OperationKind::SERVICE_DEPLOY,
|
||||
'target_type' => (new Service)->getMorphClass(),
|
||||
'target_id' => Service::factory(),
|
||||
'status' => OperationStatus::PENDING,
|
||||
];
|
||||
}
|
||||
}
|
||||
37
database/factories/ServiceFactory.php
Normal file
37
database/factories/ServiceFactory.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\DeployPolicy;
|
||||
use App\Enums\ServiceCategory;
|
||||
use App\Enums\ServiceStatus;
|
||||
use App\Enums\ServiceType;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Service>
|
||||
*/
|
||||
class ServiceFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->word(),
|
||||
'status' => ServiceStatus::NOT_INSTALLED,
|
||||
'category' => ServiceCategory::DATABASE,
|
||||
'type' => ServiceType::POSTGRES,
|
||||
'version' => '18',
|
||||
'version_track' => '18',
|
||||
'driver_name' => 'postgres.18',
|
||||
'desired_replicas' => 1,
|
||||
'deploy_policy' => DeployPolicy::DEPENDENCY_ONLY,
|
||||
'process_roles' => [],
|
||||
'config' => [],
|
||||
];
|
||||
}
|
||||
}
|
||||
33
database/factories/ServiceReplicaFactory.php
Normal file
33
database/factories/ServiceReplicaFactory.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\ServiceReplica>
|
||||
*/
|
||||
class ServiceReplicaFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'service_id' => Service::factory(),
|
||||
'server_id' => Server::factory(),
|
||||
'container_name' => $this->faker->slug(),
|
||||
'image_digest' => 'sha256:'.$this->faker->sha256(),
|
||||
'internal_host' => $this->faker->domainWord(),
|
||||
'internal_port' => 8080,
|
||||
'status' => 'running',
|
||||
'health_status' => 'healthy',
|
||||
'config' => [],
|
||||
];
|
||||
}
|
||||
}
|
||||
33
database/factories/ServiceSliceFactory.php
Normal file
33
database/factories/ServiceSliceFactory.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Service;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\ServiceSlice>
|
||||
*/
|
||||
class ServiceSliceFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'service_id' => Service::factory(),
|
||||
'name' => $this->faker->slug(),
|
||||
'type' => 'database_user',
|
||||
'status' => 'active',
|
||||
'config' => [],
|
||||
'credentials' => [
|
||||
'username' => $this->faker->userName(),
|
||||
'password' => $this->faker->password(16),
|
||||
'database' => $this->faker->slug(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,11 @@ return new class extends Migration
|
||||
$table->string('name');
|
||||
$table->string('repository_url');
|
||||
$table->string('repository_type');
|
||||
$table->string('default_branch')->default('main');
|
||||
$table->text('deploy_key_public')->nullable();
|
||||
$table->text('deploy_key_private')->nullable();
|
||||
$table->string('deploy_key_fingerprint')->nullable();
|
||||
$table->timestamp('deploy_key_installed_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Application;
|
||||
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('environments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Application::class)->constrained()->cascadeOnDelete();
|
||||
$table->string('name');
|
||||
$table->string('branch');
|
||||
$table->string('status')->default('pending');
|
||||
$table->boolean('scheduler_enabled')->default(true);
|
||||
$table->foreignId('scheduler_target_service_id')->nullable();
|
||||
$table->string('scheduler_mode')->default('single');
|
||||
$table->json('build_config')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['application_id', 'name']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('environments');
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Organisation;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
@@ -11,13 +12,26 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('services', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Server::class);
|
||||
$table->foreignIdFor(Organisation::class)->nullable();
|
||||
$table->foreignId('environment_id')->nullable();
|
||||
$table->foreignIdFor(Server::class)->nullable();
|
||||
$table->string('name');
|
||||
$table->string('status');
|
||||
$table->string('category'); // database / cache / webserver
|
||||
$table->string('type'); // postgres / redis / caddy
|
||||
$table->string('version'); // 17 / 7 / 2
|
||||
$table->string('version')->nullable(); // legacy alias for version_track
|
||||
$table->string('version_track'); // 18 / 8 / 2 / php-8.4
|
||||
$table->string('driver_name');
|
||||
$table->unsignedInteger('desired_replicas')->default(1);
|
||||
$table->string('desired_revision')->nullable();
|
||||
$table->string('deploy_policy')->default('manual');
|
||||
$table->json('process_roles')->nullable();
|
||||
$table->string('current_image_digest')->nullable();
|
||||
$table->string('available_image_digest')->nullable();
|
||||
$table->string('update_status')->nullable();
|
||||
$table->decimal('default_cpu_limit', 8, 3)->nullable();
|
||||
$table->unsignedInteger('default_memory_limit_mb')->nullable();
|
||||
$table->json('config')->nullable();
|
||||
$table->text('credentials')->nullable();
|
||||
$table->string('container_name')->nullable();
|
||||
$table->string('container_id')->nullable();
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
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('service_replicas', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Service::class)->constrained()->cascadeOnDelete();
|
||||
$table->foreignIdFor(Server::class)->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('operation_id')->nullable();
|
||||
$table->string('container_name');
|
||||
$table->string('container_id')->nullable();
|
||||
$table->string('image_digest')->nullable();
|
||||
$table->string('internal_host');
|
||||
$table->unsignedInteger('internal_port');
|
||||
$table->unsignedInteger('public_port')->nullable();
|
||||
$table->string('status')->default('pending');
|
||||
$table->string('health_status')->default('unknown');
|
||||
$table->decimal('cpu_limit', 8, 3)->nullable();
|
||||
$table->unsignedInteger('memory_limit_mb')->nullable();
|
||||
$table->json('config')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('service_replicas');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Service;
|
||||
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('service_slices', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Service::class)->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('environment_id')->nullable()->constrained('environments')->nullOnDelete();
|
||||
$table->string('name');
|
||||
$table->string('type');
|
||||
$table->string('status')->default('pending');
|
||||
$table->json('config')->nullable();
|
||||
$table->text('credentials')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['service_id', 'type', 'name']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('service_slices');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Service;
|
||||
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('environment_attachments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('environment_id')->constrained('environments')->cascadeOnDelete();
|
||||
$table->foreignIdFor(Service::class)->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('service_slice_id')->nullable()->constrained('service_slices')->nullOnDelete();
|
||||
$table->string('role');
|
||||
$table->string('env_prefix')->nullable();
|
||||
$table->boolean('is_primary')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('environment_attachments');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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('environment_variables', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('environment_id')->constrained('environments')->cascadeOnDelete();
|
||||
$table->string('key');
|
||||
$table->text('value');
|
||||
$table->string('source')->default('user');
|
||||
$table->foreignId('service_slice_id')->nullable()->constrained('service_slices')->nullOnDelete();
|
||||
$table->boolean('overridable')->default(true);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['environment_id', 'key']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('environment_variables');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Organisation;
|
||||
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('registries', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Organisation::class)->constrained()->cascadeOnDelete();
|
||||
$table->string('name');
|
||||
$table->string('type');
|
||||
$table->string('url')->nullable();
|
||||
$table->text('credentials')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('source_providers', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Organisation::class)->constrained()->cascadeOnDelete();
|
||||
$table->string('name');
|
||||
$table->string('type');
|
||||
$table->string('url')->nullable();
|
||||
$table->json('config')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('build_artifacts', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('environment_id')->constrained('environments')->cascadeOnDelete();
|
||||
$table->string('commit_sha');
|
||||
$table->string('image_tag');
|
||||
$table->string('image_digest')->nullable();
|
||||
$table->string('registry_ref')->nullable();
|
||||
$table->foreignId('built_by_operation_id')->nullable();
|
||||
$table->foreignId('built_by_service_id')->nullable()->constrained('services')->nullOnDelete();
|
||||
$table->string('status')->default('pending');
|
||||
$table->json('metadata')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['environment_id', 'commit_sha', 'image_tag']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('build_artifacts');
|
||||
Schema::dropIfExists('source_providers');
|
||||
Schema::dropIfExists('registries');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Service;
|
||||
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('service_endpoints', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Service::class)->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('service_replica_id')->nullable()->constrained('service_replicas')->nullOnDelete();
|
||||
$table->string('scope');
|
||||
$table->string('hostname');
|
||||
$table->string('ip_address')->nullable();
|
||||
$table->unsignedInteger('port');
|
||||
$table->unsignedInteger('priority')->default(100);
|
||||
$table->string('health_status')->default('unknown');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('service_endpoints');
|
||||
}
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\Server;
|
||||
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('instances', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Application::class);
|
||||
$table->foreignIdFor(Server::class);
|
||||
$table->string('branch');
|
||||
$table->string('status');
|
||||
$table->json('config')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('instances');
|
||||
}
|
||||
};
|
||||
@@ -8,9 +8,11 @@ return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('deployments', function (Blueprint $table) {
|
||||
Schema::create('operations', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('parent_id')->nullable()->constrained('operations')->nullOnDelete();
|
||||
$table->string('hash')->unique();
|
||||
$table->string('kind')->default('service_deploy');
|
||||
$table->morphs('target'); // server, service, etc.
|
||||
$table->string('status');
|
||||
$table->dateTime('started_at')->nullable();
|
||||
@@ -21,6 +23,6 @@ return new class extends Migration
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('deployments');
|
||||
Schema::dropIfExists('operations');
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Deployment;
|
||||
use App\Models\Operation;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
@@ -9,9 +9,9 @@ return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('steps', function (Blueprint $table) {
|
||||
Schema::create('operation_steps', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Deployment::class);
|
||||
$table->foreignIdFor(Operation::class);
|
||||
$table->string('name');
|
||||
$table->integer('order');
|
||||
$table->string('status');
|
||||
@@ -27,6 +27,6 @@ return new class extends Migration
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('steps');
|
||||
Schema::dropIfExists('operation_steps');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user