This commit is contained in:
Andras Bacsai 2023-03-28 15:47:37 +02:00
parent 0b248e9be4
commit 4df66ebf00
24 changed files with 408 additions and 25 deletions

View File

@ -8,7 +8,6 @@ GROUPID=
############################################################################################################
APP_NAME=Laravel
APP_SERVICE=php
APP_ENV=local
APP_KEY=
APP_DEBUG=true

View File

@ -0,0 +1,71 @@
<?php
namespace App\Http\Livewire;
use App\Models\Application;
use App\Models\CoolifyInstanceSettings;
use App\Models\Deployment;
use App\Traits\Shared;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class DemoDeployApplication extends Component
{
use Shared;
public $activity;
public $isKeepAliveOn = false;
public $application_uuid;
public Application $application;
public $destination;
public CoolifyInstanceSettings $coolify_instance_settings;
public $wildcard_domain;
public function deploy()
{
$this->isKeepAliveOn = true;
$this->coolify_instance_settings = CoolifyInstanceSettings::find(1);
$this->application = Application::where('uuid', $this->application_uuid)->first();
$this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
$project_wildcard_domain = data_get($this->application, 'environment.project.settings.wildcard_domain');
$global_wildcard_domain = data_get($this->coolify_instance_settings, 'wildcard_domain');
$this->wildcard_domain = $project_wildcard_domain ?? $global_wildcard_domain ?? null;
$source = $this->application->source->getMorphClass()::where('id', $this->application->source->id)->first();
$deployment_id = new Cuid2(10);
$workdir = $this->get_workdir('application', $this->application->uuid, $deployment_id);
$command[] = "echo 'Starting deployment of {$this->application->name} ({$this->application->uuid})'";
$command[] = 'mkdirs -p ' . $workdir;
$command[] = "git clone -b {$this->application->git_branch} {$source->html_url}/{$this->application->git_repository}.git {$workdir}";
if (!file_exists($workdir) && $workdir != "/") {
$command[] = "echo 'Removing {$workdir}'";
$command[] = "rm -rf {$workdir}";
}
$this->activity = remoteProcess(implode("\n", $command), $this->destination->server->name);
Deployment::create([
'uuid' => $deployment_id,
'type_id' => $this->application->id,
'type_type' => Application::class,
'activity_log_id' => $this->activity->id,
]);
}
public function polling()
{
$this->activity?->refresh();
if (data_get($this->activity, 'properties.exitCode') !== null) {
$this->isKeepAliveOn = false;
}
}
public function render()
{
return view('livewire.demo-deploy-application');
}
}

View File

@ -15,13 +15,15 @@ class RunCommand extends Component
public $command = 'ls';
public $server = 'testing-host';
public $server;
public $servers = [];
public function mount()
{
$this->servers = Server::all()->pluck('name')->toArray();
$this->server = $this->servers[0];
}
public function render()
{

View File

@ -8,6 +8,10 @@ public function environment()
{
return $this->belongsTo(Environment::class);
}
public function settings()
{
return $this->hasOne(ApplicationSetting::class);
}
public function destination()
{
return $this->morphTo();
@ -16,4 +20,8 @@ public function source()
{
return $this->morphTo();
}
public function deployments()
{
return $this->morphMany(Deployment::class, 'type');
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ApplicationSetting extends Model
{
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CoolifyInstanceSettings extends Model
{
use HasFactory;
}

View File

@ -12,4 +12,8 @@ public function destination()
{
return $this->morphTo();
}
public function deployments()
{
return $this->morphMany(Deployment::class, 'type');
}
}

24
app/Models/Deployment.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Models\Activity;
class Deployment extends Model
{
protected $fillable = [
'uuid',
'type_id',
'type_type',
'activity_log_id',
];
public function type()
{
return $this->morphTo();
}
public function activity()
{
return $this->belongsTo(Activity::class, 'activity_log_id');
}
}

View File

@ -4,6 +4,10 @@
class Environment extends BaseModel
{
public function project()
{
return $this->belongsTo(Project::class);
}
public function applications()
{
return $this->hasMany(Application::class);

View File

@ -8,4 +8,8 @@ public function applications()
{
return $this->morphMany(Application::class, 'destination');
}
public function server()
{
return $this->belongsTo(Server::class);
}
}

14
app/Traits/Shared.php Normal file
View File

@ -0,0 +1,14 @@
<?php
namespace App\Traits;
use Illuminate\Support\Facades\Process;
trait Shared
{
public function get_workdir(string $type, string $resource_id, string $deployment_id)
{
$workdir = "/tmp/coolify/$type/{$resource_id}/{$deployment_id}/";
return $workdir;
}
}

View File

@ -27,13 +27,16 @@ function remoteProcess(
'remoteProcessArgs' => new RemoteProcessArgs(
destination: $found_server->ip,
private_key_location: $private_key_location,
command: $command,
command: <<<EOT
{$command}
EOT,
port: $found_server->port,
user: $found_server->user,
),
])();
}
function checkServer(string $destination){
function checkServer(string $destination)
{
// @TODO: Use UUID instead of name
$found_server = Server::where('name', $destination)->first();
if (!$found_server) {
@ -41,11 +44,11 @@ function checkServer(string $destination){
};
return $found_server;
}
function checkTeam(string $team_id){
function checkTeam(string $team_id)
{
$found_team = auth()->user()->teams->pluck('id')->contains($team_id);
if (!$found_team) {
throw new \RuntimeException('You do not have access to this server.');
}
}
}

View File

@ -0,0 +1,41 @@
<?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::create('coolify_instance_settings', function (Blueprint $table) {
$table->id();
$table->string('fqdn')->nullable();
$table->string('wildcard_domain')->nullable();
$table->string('redirect_url')->nullable();
// $table->string('preview_domain_separator')->default('.');
$table->integer('public_port_min')->default(9000);
$table->integer('public_port_max')->default(9100);
// $table->string('custom_dns_servers')->default('1.1.1.1,8.8.8.8');
$table->boolean('do_not_track')->default(false);
$table->boolean('is_auto_update_enabled')->default(true);
// $table->boolean('is_dns_check_enabled')->default(true);
$table->boolean('is_registration_enabled')->default(true);
$table->boolean('is_https_forced')->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('coolify_instance_settings');
}
};

View File

@ -16,8 +16,47 @@ public function up(): void
$table->string('uuid')->unique();
$table->string('name');
$table->string('fqdn')->unique()->nullable();
$table->string('config_hash')->nullable();
$table->string('git_repository');
$table->string('git_branch');
$table->string('git_commit_sha')->nullable();
$table->string('docker_registry_image_name')->nullable();
$table->string('docker_registry_image_tag')->nullable();
$table->string('build_pack');
$table->string('base_image')->nullable();
$table->string('build_image')->nullable();
$table->string('install_command')->nullable();
$table->string('build_command')->nullable();
$table->string('start_command')->nullable();
$table->string('ports_exposes');
$table->string('ports_mappings')->nullable();
$table->string('base_directory')->default('/');
$table->string('publish_directory')->nullable();
$table->string('health_check_path')->nullable();
$table->string('health_check_port')->nullable();
$table->string('health_check_host')->default('localhost');
$table->string('health_check_method')->default('GET');
$table->integer('health_check_return_code')->default(200);
$table->string('health_check_scheme')->default('http');
$table->string('health_check_response_text')->nullable();
$table->integer('health_check_interval')->default(5);
$table->integer('health_check_timeout')->default(5);
$table->integer('health_check_retries')->default(10);
$table->integer('health_check_start_period')->default(5);
$table->string('status')->default('killed');
$table->morphs('destination');
$table->morphs('source');
$table->foreignId('environment_id');
$table->timestamps();

View File

@ -0,0 +1,37 @@
<?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::create('application_settings', function (Blueprint $table) {
$table->id();
$table->boolean('is_git_submodules_allowed')->default(true);
$table->boolean('is_git_lfs_allowed')->default(true);
$table->boolean('is_auto_deploy')->default(true);
$table->boolean('is_dual_cert')->default(false);
$table->boolean('is_debug')->default(false);
$table->boolean('is_previews')->default(false);
$table->boolean('is_bot')->default(false);
$table->boolean('is_custom_ssl')->default(false);
$table->boolean('is_http2')->default(false);
$table->foreignId('application_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('application_settings');
}
};

View File

@ -0,0 +1,30 @@
<?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::create('deployments', function (Blueprint $table) {
$table->id();
$table->string('uuid')->unique();
$table->morphs('type');
$table->foreignId('activity_log_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('deployments');
}
};

View File

@ -3,6 +3,7 @@
namespace Database\Seeders;
use App\Models\Application;
use App\Models\ApplicationSetting;
use App\Models\Environment;
use App\Models\GithubApp;
use App\Models\StandaloneDocker;
@ -24,20 +25,25 @@ public function run(): void
Application::create([
'id' => 1,
'name' => 'My first application',
'git_repository' => 'coollabsio/coolify-examples',
'git_branch' => 'nodejs-fastify',
'build_pack' => 'nixpacks',
'ports_exposes' => '3000',
'ports_mappings' => '3000:3000,3010:3001',
'environment_id' => $environment_1->id,
'destination_id' => $standalone_docker_1->id,
'destination_type' => StandaloneDocker::class,
'source_id' => $github_public_source->id,
'source_type' => GithubApp::class,
]);
Application::create([
'id' => 2,
'name' => 'My second application (Swarm)',
'environment_id' => $environment_1->id,
'destination_id' => $swarm_docker_1->id,
'destination_type' => SwarmDocker::class,
'source_id' => $github_public_source->id,
'source_type' => GithubApp::class,
]);
// Application::create([
// 'id' => 2,
// 'name' => 'My second application (Swarm)',
// 'environment_id' => $environment_1->id,
// 'destination_id' => $swarm_docker_1->id,
// 'destination_type' => SwarmDocker::class,
// 'source_id' => $github_public_source->id,
// 'source_type' => GithubApp::class,
// ]);
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Database\Seeders;
use App\Models\Application;
use App\Models\ApplicationSetting;
use App\Models\Environment;
use App\Models\GithubApp;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use Illuminate\Database\Seeder;
class ApplicationSettingsSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$application_1 = Application::find(1);
ApplicationSetting::create([
'id' => 1,
'application_id' => $application_1->id,
]);
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Database\Seeders;
use App\Models\Application;
use App\Models\ApplicationSetting;
use App\Models\CoolifyInstanceSettings;
use App\Models\Environment;
use App\Models\GithubApp;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use Illuminate\Database\Seeder;
class CoolifyInstanceSettingsSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
CoolifyInstanceSettings::create([
'id' => 1,
'wildcard_domain' => 'coolify.io',
'is_https_forced' => false,
'is_registration_enabled' => true,
]);
}
}

View File

@ -9,6 +9,7 @@ class DatabaseSeeder extends Seeder
public function run(): void
{
$this->call([
CoolifyInstanceSettingsSeeder::class,
UserSeeder::class,
TeamSeeder::class,
PrivateKeySeeder::class,
@ -22,6 +23,7 @@ public function run(): void
GithubAppSeeder::class,
GitlabAppSeeder::class,
ApplicationSeeder::class,
ApplicationSettingsSeeder::class,
DBSeeder::class,
ServiceSeeder::class,
]);

View File

@ -5,9 +5,7 @@
use App\Models\PrivateKey;
use App\Models\Server;
use App\Models\Team;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class ServerSeeder extends Seeder
{
@ -18,9 +16,10 @@ public function run(): void
{
$root_team = Team::find(1);
$private_key_1 = PrivateKey::find(1);
Server::create([
'id' => 1,
'name' => "testing-host",
'name' => "testing-local-docker-container",
'description' => "This is a test docker container",
'ip' => "coolify-testing-host",
'team_id' => $root_team->id,
@ -28,12 +27,20 @@ public function run(): void
]);
Server::create([
'id' => 2,
'name' => "testing-host2",
'name' => "testing-local-docker-container-2",
'description' => "This is a test docker container",
'ip' => "coolify-testing-host-2",
'team_id' => $root_team->id,
'private_key_id' => $private_key_1->id,
]);
Server::create([
'id' => 3,
'name' => "localhost",
'description' => "This is the local machine",
'user' => 'ab',
'ip' => "172.17.0.1",
'team_id' => $root_team->id,
'private_key_id' => $private_key_1->id,
]);
}
}

View File

@ -15,10 +15,10 @@ class StandaloneDockerSeeder extends Seeder
*/
public function run(): void
{
$server_1 = Server::find(1);
$server_3 = Server::find(3);
StandaloneDocker::create([
'id' => 1,
'server_id' => $server_1->id,
'server_id' => $server_3->id,
]);
}
}

View File

@ -13,9 +13,10 @@
<h2>Applications</h2>
@forelse ($environment->applications as $application)
<h3>{{ $application->name }}</h3>
<p>Application: {{ $application }}</p>
<p>Application: {{ $application->settings }}</p>
<p>Destination Class: {{ $application->destination->getMorphClass() }}</p>
<p>Source Class: {{ $application->source->getMorphClass() }}</p>
<livewire:demo-deploy-application :application_uuid="$application->uuid" />
@empty
<li>No application found</li>
@endforelse

View File

@ -0,0 +1,13 @@
<div>
@isset($activity?->id)
<div>
Activity: <span>{{ $activity?->id ?? 'waiting' }}</span>
</div>
<pre style="width: 100%;overflow-y: scroll;" @if ($isKeepAliveOn) wire:poll.750ms="polling" @endif>{{ data_get($activity, 'description') }}</pre>
{{-- <div>
<div>Details:</div>
<pre style="width: 100%;overflow-y: scroll;">{{ json_encode(data_get($activity, 'properties'), JSON_PRETTY_PRINT) }}</pre>
</div> --}}
@endisset
<button wire:click='deploy'>Deploy</button>
</div>