From da2f6573421c4eb387c00e3e2e55c049b593e53d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 30 Mar 2023 15:52:19 +0200 Subject: [PATCH 01/12] wip --- .../RemoteProcess/RunRemoteProcess.php | 17 +--- app/Http/Livewire/DeployApplication.php | 4 +- app/Jobs/ContainerStatusJob.php | 61 +++++++++++++++ app/Models/Server.php | 12 +++ app/Models/ServerSetting.php | 11 +++ bootstrap/helpers.php | 77 +++++++++++++++++-- composer.lock | 72 ++++++++--------- ...24_140712_create_server_settings_table.php | 31 ++++++++ database/seeders/ApplicationSeeder.php | 4 +- database/seeders/DBSeeder.php | 14 ++-- database/seeders/ServiceSeeder.php | 14 ++-- .../demo-deploy-application.blade.php | 9 --- resources/views/project/application.blade.php | 5 +- tests/Feature/DockerCommandsTest.php | 4 +- tests/Support/Output.php | 17 ---- 15 files changed, 245 insertions(+), 107 deletions(-) create mode 100644 app/Jobs/ContainerStatusJob.php create mode 100644 app/Models/ServerSetting.php create mode 100644 database/migrations/2023_03_24_140712_create_server_settings_table.php delete mode 100644 resources/views/livewire/demo-deploy-application.blade.php delete mode 100644 tests/Support/Output.php diff --git a/app/Actions/RemoteProcess/RunRemoteProcess.php b/app/Actions/RemoteProcess/RunRemoteProcess.php index 790f21efd..038b681a8 100644 --- a/app/Actions/RemoteProcess/RunRemoteProcess.php +++ b/app/Actions/RemoteProcess/RunRemoteProcess.php @@ -70,22 +70,7 @@ protected function getCommand(): string $port = $this->activity->getExtraProperty('port'); $command = $this->activity->getExtraProperty('command'); - $delimiter = 'EOF-COOLIFY-SSH'; - Storage::disk('local')->makeDirectory('.ssh'); - - $ssh_command = "ssh " - . "-i {$private_key_location} " - . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' - . '-o PasswordAuthentication=no ' - . '-o RequestTTY=no ' - . '-o LogLevel=ERROR ' - . '-o ControlMaster=auto -o ControlPersist=1m -o ControlPath=/var/www/html/storage/app/.ssh/ssh_mux_%h_%p_%r ' - . "-p {$port} " - . "{$user}@{$server_ip} " - . " 'bash -se' << \\$delimiter" . PHP_EOL - . $command . PHP_EOL - . $delimiter; - return $ssh_command; + return generateSshCommand($private_key_location, $server_ip, $user, $port, $command); } protected function handleOutput(string $type, string $output) diff --git a/app/Http/Livewire/DeployApplication.php b/app/Http/Livewire/DeployApplication.php index 461fe0765..9a5deb245 100644 --- a/app/Http/Livewire/DeployApplication.php +++ b/app/Http/Livewire/DeployApplication.php @@ -2,6 +2,7 @@ namespace App\Http\Livewire; +use App\Jobs\ContainerStatusJob; use App\Models\Application; use App\Models\CoolifyInstanceSettings; use DateTimeImmutable; @@ -220,7 +221,7 @@ public function deploy() $this->execute_in_builder("docker build -f {$workdir}/Dockerfile --build-arg SOURCE_COMMIT=$(cat {$workdir}/.git-commit) --progress plain -t {$this->application->uuid}:$(cat {$workdir}/.git-commit) {$workdir}"); $this->command[] = "echo 'Done.'"; - $this->execute_in_builder("test ! -z \"$(docker ps --format '{{.State}}' --filter 'name={$this->application->uuid}')\" && docker rm -f {$this->application->uuid} >/dev/null 2>&1"); + // $this->execute_in_builder("test ! -z \"$(docker ps --format '{{.State}}' --filter 'name={$this->application->uuid}')\" && docker rm -f {$this->application->uuid} >/dev/null 2>&1"); $this->command[] = "echo -n 'Deploying... '"; @@ -235,6 +236,7 @@ public function deploy() } public function cancel() { + ContainerStatusJob::dispatch(); } public function render() { diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php new file mode 100644 index 000000000..6ece825ea --- /dev/null +++ b/app/Jobs/ContainerStatusJob.php @@ -0,0 +1,61 @@ +where('settings->is_build_server', '=', false)->first(); + $applications = Application::all(); + $not_found_applications = $applications; + $containers = []; + // foreach ($servers as $server) { + $private_key_location = savePrivateKey($server); + $ssh_command = generateSshCommand($private_key_location, $server->ip, $server->user, $server->port, 'docker ps -a -q --format \'{{json .}}\''); + $process = Process::run($ssh_command); + $output = trim($process->output()); + $containers = formatDockerCmdOutputToJson($output); + foreach ($containers as $container) { + $found_application = $applications->filter(function ($value, $key) use ($container) { + return $value->uuid == $container['Names']; + })->first(); + if ($found_application) { + $not_found_applications = $not_found_applications->filter(function ($value, $key) use ($found_application) { + return $value->uuid != $found_application->uuid; + }); + $found_application->status = $container['State']; + $found_application->save(); + Log::info('Found application: ' . $found_application->uuid . ' settings status to: ' . $found_application->status); + } + } + foreach ($not_found_applications as $not_found_application) { + $not_found_application->status = 'exited'; + $not_found_application->save(); + Log::info('Not found application: ' . $not_found_application->uuid . ' settings status to: ' . $not_found_application->status); + } + } catch (\Exception $e) { + Log::error($e->getMessage()); + } + } +} diff --git a/app/Models/Server.php b/app/Models/Server.php index 2f5e67971..da302d056 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -4,8 +4,20 @@ class Server extends BaseModel { + protected static function booted() + { + static::created(function ($server) { + ServerSetting::create([ + 'server_id' => $server->id, + ]); + }); + } public function privateKey() { return $this->belongsTo(PrivateKey::class); } + public function settings() + { + return $this->hasOne(ServerSetting::class); + } } diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php new file mode 100644 index 000000000..7b76e829c --- /dev/null +++ b/app/Models/ServerSetting.php @@ -0,0 +1,11 @@ +belongsTo(Server::class); + } +} diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index 86bc7a6e0..64e2fa8b2 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -5,6 +5,8 @@ use App\Enums\ActivityTypes; use App\Models\Server; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Collection; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; use Spatie\Activitylog\Contracts\Activity; @@ -24,9 +26,7 @@ function remoteProcess( // @TODO: Check if the user has access to this server // checkTeam($server->team_id); - $temp_file = 'id.rsa_' . 'root' . '@' . $server->ip; - Storage::disk('local')->put($temp_file, $server->privateKey->private_key, 'private'); - $private_key_location = '/var/www/html/storage/app/' . $temp_file; + $private_key_location = savePrivateKey($server); return resolve(DispatchRemoteProcess::class, [ 'remoteProcessArgs' => new RemoteProcessArgs( @@ -43,11 +43,72 @@ function remoteProcess( ), ])(); } - 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.'); + // } + // } +} + +if (!function_exists('savePrivateKey')) { + function savePrivateKey(Server $server) { - $found_team = auth()->user()->teams->pluck('id')->contains($team_id); - if (!$found_team) { - throw new \RuntimeException('You do not have access to this server.'); - } + $temp_file = 'id.rsa_' . 'root' . '@' . $server->ip; + Storage::disk('local')->put($temp_file, $server->privateKey->private_key, 'private'); + return '/var/www/html/storage/app/' . $temp_file; } } + +if (!function_exists('generateSshCommand')) { + function generateSshCommand(string $private_key_location, string $server_ip, string $user, string $port, $command) + { + $delimiter = 'EOF-COOLIFY-SSH'; + Storage::disk('local')->makeDirectory('.ssh'); + $ssh_command = "ssh " + . "-i {$private_key_location} " + . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' + . '-o PasswordAuthentication=no ' + . '-o RequestTTY=no ' + . '-o LogLevel=ERROR ' + . '-o ControlMaster=auto -o ControlPersist=1m -o ControlPath=/var/www/html/storage/app/.ssh/ssh_mux_%h_%p_%r ' + . "-p {$port} " + . "{$user}@{$server_ip} " + . " 'bash -se' << \\$delimiter" . PHP_EOL + . $command . PHP_EOL + . $delimiter; + return $ssh_command; + } +} +if (!function_exists('formatDockerCmdOutputToJson')) { + function formatDockerCmdOutputToJson($rawOutput): Collection + { + $outputLines = explode(PHP_EOL, $rawOutput); + + return collect($outputLines) + ->reject(fn ($line) => empty($line)) + ->map(fn ($outputLine) => json_decode($outputLine, true, flags: JSON_THROW_ON_ERROR)); + } +} +if (!function_exists('formatDockerLabelsToJson')) { + function formatDockerLabelsToJson($rawOutput): Collection + { + $outputLines = explode(PHP_EOL, $rawOutput); + + return collect($outputLines) + ->reject(fn ($line) => empty($line)) + ->map(function ($outputLine) { + $outputArray = explode(',', $outputLine); + return collect($outputArray) + ->map(function ($outputLine) { + return explode('=', $outputLine); + }) + ->mapWithKeys(function ($outputLine) { + return [$outputLine[0] => $outputLine[1]]; + }); + })[0]; + + } +} + diff --git a/composer.lock b/composer.lock index 28478c6fd..87f668056 100644 --- a/composer.lock +++ b/composer.lock @@ -1193,16 +1193,16 @@ }, { "name": "laravel/framework", - "version": "v10.4.1", + "version": "v10.5.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "7d15f7eef442633cff108f83d9fe43d8c3b8b76f" + "reference": "485f22333e8c1dff5bae0fe0421c1e2e139713de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/7d15f7eef442633cff108f83d9fe43d8c3b8b76f", - "reference": "7d15f7eef442633cff108f83d9fe43d8c3b8b76f", + "url": "https://api.github.com/repos/laravel/framework/zipball/485f22333e8c1dff5bae0fe0421c1e2e139713de", + "reference": "485f22333e8c1dff5bae0fe0421c1e2e139713de", "shasum": "" }, "require": { @@ -1389,7 +1389,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-03-18T11:34:02+00:00" + "time": "2023-03-29T15:09:16+00:00" }, { "name": "laravel/sanctum", @@ -2683,16 +2683,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.7.0", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5" + "reference": "dfc078e8af9c99210337325ff5aa152872c98714" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5", - "reference": "1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714", + "reference": "dfc078e8af9c99210337325ff5aa152872c98714", "shasum": "" }, "require": { @@ -2735,9 +2735,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1" }, - "time": "2023-03-12T10:13:29+00:00" + "time": "2023-03-27T19:02:04+00:00" }, { "name": "phpoption/phpoption", @@ -3378,16 +3378,16 @@ }, { "name": "psy/psysh", - "version": "v0.11.13", + "version": "v0.11.14", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "722317c9f5627e588788e340f29b923e58f92f54" + "reference": "8c2e264def7a8263a68ef6f0b55ce90b77d41e17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/722317c9f5627e588788e340f29b923e58f92f54", - "reference": "722317c9f5627e588788e340f29b923e58f92f54", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/8c2e264def7a8263a68ef6f0b55ce90b77d41e17", + "reference": "8c2e264def7a8263a68ef6f0b55ce90b77d41e17", "shasum": "" }, "require": { @@ -3448,9 +3448,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.11.13" + "source": "https://github.com/bobthecow/psysh/tree/v0.11.14" }, - "time": "2023-03-21T14:22:44+00:00" + "time": "2023-03-28T03:41:01+00:00" }, { "name": "ralouphie/getallheaders", @@ -7534,16 +7534,16 @@ }, { "name": "laravel/sail", - "version": "v1.21.2", + "version": "v1.21.3", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "19d6fe167e2389b41fe1b4ee52293d1eaf8a43fc" + "reference": "3042ff8cf403817c340d5a7762b2d32900239f46" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/19d6fe167e2389b41fe1b4ee52293d1eaf8a43fc", - "reference": "19d6fe167e2389b41fe1b4ee52293d1eaf8a43fc", + "url": "https://api.github.com/repos/laravel/sail/zipball/3042ff8cf403817c340d5a7762b2d32900239f46", + "reference": "3042ff8cf403817c340d5a7762b2d32900239f46", "shasum": "" }, "require": { @@ -7595,7 +7595,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2023-03-06T14:23:15+00:00" + "time": "2023-03-13T01:22:10+00:00" }, { "name": "mockery/mockery", @@ -7889,16 +7889,16 @@ }, { "name": "pestphp/pest", - "version": "v2.2.3", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "6c8970e0a3b9bb36544bb1eacba0a4175dbafe97" + "reference": "5ae061d2080ea09608fe37fb05ebadcd183cef85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/6c8970e0a3b9bb36544bb1eacba0a4175dbafe97", - "reference": "6c8970e0a3b9bb36544bb1eacba0a4175dbafe97", + "url": "https://api.github.com/repos/pestphp/pest/zipball/5ae061d2080ea09608fe37fb05ebadcd183cef85", + "reference": "5ae061d2080ea09608fe37fb05ebadcd183cef85", "shasum": "" }, "require": { @@ -7908,10 +7908,10 @@ "pestphp/pest-plugin": "^2.0.1", "pestphp/pest-plugin-arch": "^2.0.2", "php": "^8.1.0", - "phpunit/phpunit": "^10.0.18" + "phpunit/phpunit": "^10.0.19" }, "conflict": { - "phpunit/phpunit": ">10.0.18", + "phpunit/phpunit": ">10.0.19", "webmozart/assert": "<1.11.0" }, "require-dev": { @@ -7972,7 +7972,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v2.2.3" + "source": "https://github.com/pestphp/pest/tree/v2.3.0" }, "funding": [ { @@ -7984,7 +7984,7 @@ "type": "github" } ], - "time": "2023-03-24T11:26:54+00:00" + "time": "2023-03-28T09:16:29+00:00" }, { "name": "pestphp/pest-plugin", @@ -8606,16 +8606,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.0.18", + "version": "10.0.19", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "582563ed2edc62d1455cdbe00ea49fe09428eef3" + "reference": "20c23e85c86e5c06d63538ba464e8054f4744e62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/582563ed2edc62d1455cdbe00ea49fe09428eef3", - "reference": "582563ed2edc62d1455cdbe00ea49fe09428eef3", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/20c23e85c86e5c06d63538ba464e8054f4744e62", + "reference": "20c23e85c86e5c06d63538ba464e8054f4744e62", "shasum": "" }, "require": { @@ -8687,7 +8687,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.0.18" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.0.19" }, "funding": [ { @@ -8703,7 +8703,7 @@ "type": "tidelift" } ], - "time": "2023-03-22T06:15:31+00:00" + "time": "2023-03-27T11:46:33+00:00" }, { "name": "sebastian/cli-parser", diff --git a/database/migrations/2023_03_24_140712_create_server_settings_table.php b/database/migrations/2023_03_24_140712_create_server_settings_table.php new file mode 100644 index 000000000..a82f49a92 --- /dev/null +++ b/database/migrations/2023_03_24_140712_create_server_settings_table.php @@ -0,0 +1,31 @@ +id(); + $table->string('uuid')->unique(); + $table->boolean('is_build_server')->default(false); + + $table->foreignId('server_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('server_settings'); + } +}; diff --git a/database/seeders/ApplicationSeeder.php b/database/seeders/ApplicationSeeder.php index ccfa74045..3a8fcde68 100644 --- a/database/seeders/ApplicationSeeder.php +++ b/database/seeders/ApplicationSeeder.php @@ -25,7 +25,7 @@ public function run(): void $github_private_source = GithubApp::find(2); Application::create([ 'id' => 1, - 'name' => 'My first application', + 'name' => 'Public application (from GitHub)', 'git_repository' => 'coollabsio/coolify-examples', 'git_branch' => 'nodejs-fastify', 'build_pack' => 'nixpacks', @@ -39,7 +39,7 @@ public function run(): void ]); Application::create([ 'id' => 2, - 'name' => 'My second application', + 'name' => 'Private application (through GitHub App)', 'git_repository' => 'coollabsio/nodejs-example', 'git_branch' => 'main', 'build_pack' => 'nixpacks', diff --git a/database/seeders/DBSeeder.php b/database/seeders/DBSeeder.php index 68bbeb01c..35effa0c6 100644 --- a/database/seeders/DBSeeder.php +++ b/database/seeders/DBSeeder.php @@ -13,12 +13,12 @@ public function run(): void { $environment_1 = Environment::find(1); $standalone_docker_1 = StandaloneDocker::find(1); - Database::create([ - 'id' => 1, - 'name'=> "My first database", - 'environment_id' => $environment_1->id, - 'destination_id' => $standalone_docker_1->id, - 'destination_type' => StandaloneDocker::class, - ]); + // Database::create([ + // 'id' => 1, + // 'name'=> "My first database", + // 'environment_id' => $environment_1->id, + // 'destination_id' => $standalone_docker_1->id, + // 'destination_type' => StandaloneDocker::class, + // ]); } } diff --git a/database/seeders/ServiceSeeder.php b/database/seeders/ServiceSeeder.php index f79b72144..360c946c5 100644 --- a/database/seeders/ServiceSeeder.php +++ b/database/seeders/ServiceSeeder.php @@ -16,12 +16,12 @@ public function run(): void { $environment_1 = Environment::find(1); $standalone_docker_1 = StandaloneDocker::find(1); - Service::create([ - 'id' => 1, - 'name'=> "My first service", - 'environment_id' => $environment_1->id, - 'destination_id' => $standalone_docker_1->id, - 'destination_type' => StandaloneDocker::class, - ]); + // Service::create([ + // 'id' => 1, + // 'name'=> "My first service", + // 'environment_id' => $environment_1->id, + // 'destination_id' => $standalone_docker_1->id, + // 'destination_type' => StandaloneDocker::class, + // ]); } } diff --git a/resources/views/livewire/demo-deploy-application.blade.php b/resources/views/livewire/demo-deploy-application.blade.php deleted file mode 100644 index 628c5de78..000000000 --- a/resources/views/livewire/demo-deploy-application.blade.php +++ /dev/null @@ -1,9 +0,0 @@ -
- @isset($activity?->id) -
- Activity: {{ $activity?->id ?? 'waiting' }} -
-
{{ data_get($activity, 'description') }}
- @endisset - -
diff --git a/resources/views/project/application.blade.php b/resources/views/project/application.blade.php index db9ba59ee..4a87abef2 100644 --- a/resources/views/project/application.blade.php +++ b/resources/views/project/application.blade.php @@ -1,7 +1,8 @@

Application

-

Name: {{ $project->name }}

-

UUID: {{ $project->uuid }}

+

Name: {{ $application->name }}

+

Application UUID: {{ $application->uuid }}

+

Status: {{ $application->status }}

Deployments

diff --git a/tests/Feature/DockerCommandsTest.php b/tests/Feature/DockerCommandsTest.php index a8418efc1..377777921 100644 --- a/tests/Feature/DockerCommandsTest.php +++ b/tests/Feature/DockerCommandsTest.php @@ -15,7 +15,7 @@ // Assert there's no containers start with coolify_test_* $activity = remoteProcess([$areThereCoolifyTestContainers], $host); - $containers = Output::containerList($activity->getExtraProperty('stdout')); + $containers = formatDockerCmdOutputToJson($activity->getExtraProperty('stdout')); expect($containers)->toBeEmpty(); // start a container nginx -d --name = $containerName @@ -24,7 +24,7 @@ // docker ps name = $container $activity = remoteProcess([$areThereCoolifyTestContainers], $host); - $containers = Output::containerList($activity->getExtraProperty('stdout')); + $containers = formatDockerCmdOutputToJson($activity->getExtraProperty('stdout')); expect($containers->where('Names', $containerName)->count())->toBe(1); // Stop testing containers diff --git a/tests/Support/Output.php b/tests/Support/Output.php deleted file mode 100644 index a3bd2c52e..000000000 --- a/tests/Support/Output.php +++ /dev/null @@ -1,17 +0,0 @@ -reject(fn($line) => empty($line)) - ->map(fn($outputLine) => json_decode($outputLine, flags: JSON_THROW_ON_ERROR)); - } -} From 8019dc12670283ca790a255c068e0bb65d6e5906 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 30 Mar 2023 17:29:01 +0200 Subject: [PATCH 02/12] wip --- app/Http/Controllers/ProjectController.php | 80 +++----------------- app/Http/Livewire/DeployApplication.php | 2 +- app/Models/Project.php | 1 + resources/views/project/deployment.blade.php | 3 - resources/views/project/resources.blade.php | 6 +- routes/web.php | 8 +- 6 files changed, 19 insertions(+), 81 deletions(-) diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index d6cadf308..3641d3200 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -2,6 +2,8 @@ namespace App\Http\Controllers; +use App\Models\Application; +use App\Models\Environment; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -9,8 +11,7 @@ class ProjectController extends Controller { public function environments() { - $project_uuid = request()->route('project_uuid'); - $project = session('currentTeam')->projects->where('uuid', $project_uuid)->first(); + $project = session('currentTeam')->projects->where('uuid', request()->route('project_uuid'))->first(); if (!$project) { return redirect()->route('home'); } @@ -18,94 +19,33 @@ public function environments() } public function resources() { - $project_uuid = request()->route('project_uuid'); - $project = session('currentTeam')->projects->where('uuid', $project_uuid)->first(); + $project = session('currentTeam')->projects->where('uuid', request()->route('project_uuid'))->first(); if (!$project) { return redirect()->route('home'); } - $environment = $project->environments->where('name', request()->route('environment_name'))->first(); + $environment = Environment::where('name', request()->route('environment_name'))->where('project_id', $project->id)->first(); + // $environment = $project->environments->where('name', request()->route('environment_name'))->first(); return view('project.resources', ['project' => $project, 'environment' => $environment]); } public function application() { - $project_uuid = request()->route('project_uuid'); - $environment_name = request()->route('environment_name'); - $application_uuid = request()->route('application_uuid'); - $project = session('currentTeam')->projects->where('uuid', $project_uuid)->first(); - if (!$project) { - return redirect()->route('home'); - } - $environment = $project->environments->where('name', $environment_name)->first(); - if (!$environment) { - return redirect()->route('home'); - } - $application = $environment->applications->where('uuid', $application_uuid)->first(); + $application = Application::where('uuid', request()->route('application_uuid'))->first(); if (!$application) { return redirect()->route('home'); } - return view('project.application', ['project' => $project, 'application' => $application, 'deployments' => $application->deployments()]); + return view('project.application', ['application' => $application, 'deployments' => $application->deployments()]); } - public function database() - { - $project_uuid = request()->route('project_uuid'); - $environment_name = request()->route('environment_name'); - $database_uuid = request()->route('database_uuid'); - $project = session('currentTeam')->projects->where('uuid', $project_uuid)->first(); - if (!$project) { - return redirect()->route('home'); - } - $environment = $project->environments->where('name', $environment_name)->first(); - if (!$environment) { - return redirect()->route('home'); - } - $database = $environment->databases->where('uuid', $database_uuid)->first(); - if (!$database) { - return redirect()->route('home'); - } - return view('project.database', ['project' => $project, 'database' => $database]); - } - public function service() - { - $project_uuid = request()->route('project_uuid'); - $environment_name = request()->route('environment_name'); - $service_uuid = request()->route('service_uuid'); - - $project = session('currentTeam')->projects->where('uuid', $project_uuid)->first(); - if (!$project) { - return redirect()->route('home'); - } - $environment = $project->environments->where('name', $environment_name)->first(); - if (!$environment) { - return redirect()->route('home'); - } - $service = $environment->services->where('uuid', $service_uuid)->first(); - if (!$service) { - return redirect()->route('home'); - } - - return view('project.service', ['project' => $project, 'service' => $service]); - } public function deployment() { - $project_uuid = request()->route('project_uuid'); - $environment_name = request()->route('environment_name'); $application_uuid = request()->route('application_uuid'); $deployment_uuid = request()->route('deployment_uuid'); - $project = session('currentTeam')->projects->where('uuid', $project_uuid)->first(); - if (!$project) { - return redirect()->route('home'); - } - $environment = $project->environments->where('name', $environment_name)->first(); - if (!$environment) { - return redirect()->route('home'); - } - $application = $environment->applications->where('uuid', $application_uuid)->first(); + $application = Application::where('uuid', request()->route('application_uuid'))->first(); if (!$application) { return redirect()->route('home'); } $activity = $application->get_deployment($deployment_uuid); - return view('project.deployment', ['project' => $project, 'activity' => $activity]); + return view('project.deployment', ['activity' => $activity]); } } diff --git a/app/Http/Livewire/DeployApplication.php b/app/Http/Livewire/DeployApplication.php index 9a5deb245..5891743c3 100644 --- a/app/Http/Livewire/DeployApplication.php +++ b/app/Http/Livewire/DeployApplication.php @@ -221,7 +221,7 @@ public function deploy() $this->execute_in_builder("docker build -f {$workdir}/Dockerfile --build-arg SOURCE_COMMIT=$(cat {$workdir}/.git-commit) --progress plain -t {$this->application->uuid}:$(cat {$workdir}/.git-commit) {$workdir}"); $this->command[] = "echo 'Done.'"; - // $this->execute_in_builder("test ! -z \"$(docker ps --format '{{.State}}' --filter 'name={$this->application->uuid}')\" && docker rm -f {$this->application->uuid} >/dev/null 2>&1"); + $this->execute_in_builder("docker rm -f {$this->application->uuid} >/dev/null 2>&1"); $this->command[] = "echo -n 'Deploying... '"; diff --git a/app/Models/Project.php b/app/Models/Project.php index 1b0a71049..0ebaf9d70 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -4,6 +4,7 @@ class Project extends BaseModel { + protected $with = ['settings', 'environments']; protected static function booted() { static::created(function ($project) { diff --git a/resources/views/project/deployment.blade.php b/resources/views/project/deployment.blade.php index 4d58b00ac..c49e8112e 100644 --- a/resources/views/project/deployment.blade.php +++ b/resources/views/project/deployment.blade.php @@ -1,7 +1,4 @@

Deployment

-

Name: {{ $project->name }}

-

UUID: {{ $project->uuid }}

-
diff --git a/resources/views/project/resources.blade.php b/resources/views/project/resources.blade.php index cdc5946ef..24f14d757 100644 --- a/resources/views/project/resources.blade.php +++ b/resources/views/project/resources.blade.php @@ -3,12 +3,12 @@
@foreach ($environment->applications as $application)

- + {{ $application->name }}

@endforeach - @foreach ($environment->databases as $database) + {{-- @foreach ($environment->databases as $database)

{{ $database->name }} @@ -21,6 +21,6 @@ {{ $service->name }}

- @endforeach + @endforeach --}}
diff --git a/routes/web.php b/routes/web.php index 067b0536f..f790904fa 100644 --- a/routes/web.php +++ b/routes/web.php @@ -23,11 +23,11 @@ Route::get('/project/{project_uuid}/{environment_name}', [ProjectController::class, 'resources'])->name('project.resources'); - Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}', [ProjectController::class, 'application'])->name('project.application'); - Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/deployment/{deployment_uuid}', [ProjectController::class, 'deployment'])->name('project.deployment'); + Route::get('/application/{application_uuid}', [ProjectController::class, 'application'])->name('project.application'); + Route::get('/application/{application_uuid}/deployment/{deployment_uuid}', [ProjectController::class, 'deployment'])->name('project.deployment'); - Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}', [ProjectController::class, 'database'])->name('project.database'); - Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}', [ProjectController::class, 'service'])->name('project.service'); + // Route::get('/database/{database_uuid}', [ProjectController::class, 'database'])->name('project.database'); + // Route::get('//service/{service_uuid}', [ProjectController::class, 'service'])->name('project.service'); Route::get('/profile', function () { return view('profile'); From 19ec042a0a8715df12132ad9888e05065aaab321 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 30 Mar 2023 19:50:27 +0200 Subject: [PATCH 03/12] wip --- app/Http/Controllers/HomeController.php | 2 +- app/Http/Controllers/ProjectController.php | 21 +++++++++++++------ app/Models/Project.php | 3 +++ app/Models/Team.php | 3 +++ .../views/project/environments.blade.php | 1 - resources/views/project/resources.blade.php | 2 +- routes/web.php | 4 ++-- 7 files changed, 25 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index f3e987682..7e96700a0 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -6,7 +6,7 @@ class HomeController extends Controller { public function show() { - $projects = session('currentTeam')->projects; + $projects = session('currentTeam')->load(['projects'])->projects; return view('home', ['projects' => $projects]); } } diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index 3641d3200..dbca37172 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -11,7 +11,7 @@ class ProjectController extends Controller { public function environments() { - $project = session('currentTeam')->projects->where('uuid', request()->route('project_uuid'))->first(); + $project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first()->load(['environments']); if (!$project) { return redirect()->route('home'); } @@ -19,17 +19,27 @@ public function environments() } public function resources() { - $project = session('currentTeam')->projects->where('uuid', request()->route('project_uuid'))->first(); + $project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); if (!$project) { return redirect()->route('home'); } - $environment = Environment::where('name', request()->route('environment_name'))->where('project_id', $project->id)->first(); - // $environment = $project->environments->where('name', request()->route('environment_name'))->first(); + $environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first(); + if (!$environment) { + return redirect()->route('home'); + } return view('project.resources', ['project' => $project, 'environment' => $environment]); } public function application() { - $application = Application::where('uuid', request()->route('application_uuid'))->first(); + $project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); + if (!$project) { + return redirect()->route('home'); + } + $environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']); + if (!$environment) { + return redirect()->route('home'); + } + $application = $environment->applications->where('uuid', request()->route('application_uuid'))->first(); if (!$application) { return redirect()->route('home'); } @@ -38,7 +48,6 @@ public function application() public function deployment() { - $application_uuid = request()->route('application_uuid'); $deployment_uuid = request()->route('deployment_uuid'); $application = Application::where('uuid', request()->route('application_uuid'))->first(); diff --git a/app/Models/Project.php b/app/Models/Project.php index 0ebaf9d70..7dc0ef613 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -19,4 +19,7 @@ public function environments() { public function settings() { return $this->hasOne(ProjectSetting::class); } + public function applications() { + return $this->hasManyThrough(Application::class, Environment::class); + } } diff --git a/app/Models/Team.php b/app/Models/Team.php index 3b05aa1ee..55ffe6afb 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -16,4 +16,7 @@ public function projects() { public function servers() { return $this->hasMany(Server::class); } + public function applications() { + return $this->hasManyThrough(Application::class, Project::class); + } } diff --git a/resources/views/project/environments.blade.php b/resources/views/project/environments.blade.php index bf9efb655..ceb0a579c 100644 --- a/resources/views/project/environments.blade.php +++ b/resources/views/project/environments.blade.php @@ -1,6 +1,5 @@

Environments

- @foreach ($project->environments as $environment)
diff --git a/resources/views/project/resources.blade.php b/resources/views/project/resources.blade.php index 24f14d757..cf451b2c5 100644 --- a/resources/views/project/resources.blade.php +++ b/resources/views/project/resources.blade.php @@ -3,7 +3,7 @@
@foreach ($environment->applications as $application)

- + {{ $application->name }}

diff --git a/routes/web.php b/routes/web.php index f790904fa..17e02d287 100644 --- a/routes/web.php +++ b/routes/web.php @@ -23,8 +23,8 @@ Route::get('/project/{project_uuid}/{environment_name}', [ProjectController::class, 'resources'])->name('project.resources'); - Route::get('/application/{application_uuid}', [ProjectController::class, 'application'])->name('project.application'); - Route::get('/application/{application_uuid}/deployment/{deployment_uuid}', [ProjectController::class, 'deployment'])->name('project.deployment'); + Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}', [ProjectController::class, 'application'])->name('project.application'); + // Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/deployment/{deployment_uuid}', [ProjectController::class, 'deployment'])->name('project.deployment'); // Route::get('/database/{database_uuid}', [ProjectController::class, 'database'])->name('project.database'); // Route::get('//service/{service_uuid}', [ProjectController::class, 'service'])->name('project.service'); From 12ef88b90f7ed395d37efac99a235af8be420375 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 30 Mar 2023 20:19:11 +0200 Subject: [PATCH 04/12] wip --- app/Console/Kernel.php | 2 ++ app/Http/Controllers/ProjectController.php | 10 ++++++++- app/Http/Livewire/DeployApplication.php | 22 ++++++++++++++----- app/Jobs/ContainerStatusJob.php | 4 ++-- .../livewire/deploy-application.blade.php | 3 ++- .../views/livewire/poll-activity.blade.php | 2 +- routes/web.php | 2 +- 7 files changed, 33 insertions(+), 12 deletions(-) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index e6b9960ec..c38638275 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,6 +2,7 @@ namespace App\Console; +use App\Jobs\ContainerStatusJob; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -12,6 +13,7 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule): void { + $schedule->job(new ContainerStatusJob)->everyMinute(); // $schedule->command('inspire')->hourly(); } diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index dbca37172..f9bc0e8bb 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -50,7 +50,15 @@ public function deployment() { $deployment_uuid = request()->route('deployment_uuid'); - $application = Application::where('uuid', request()->route('application_uuid'))->first(); + $project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); + if (!$project) { + return redirect()->route('home'); + } + $environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']); + if (!$environment) { + return redirect()->route('home'); + } + $application = $environment->applications->where('uuid', request()->route('application_uuid'))->first(); if (!$application) { return redirect()->route('home'); } diff --git a/app/Http/Livewire/DeployApplication.php b/app/Http/Livewire/DeployApplication.php index 5891743c3..fac2c305c 100644 --- a/app/Http/Livewire/DeployApplication.php +++ b/app/Http/Livewire/DeployApplication.php @@ -27,6 +27,13 @@ class DeployApplication extends Component protected $destination; protected $source; + public function mount($application_uuid) { + $this->application_uuid = $application_uuid; + } + public function render() + { + return view('livewire.deploy-application'); + } private function execute_in_builder(string $command) { if ($this->application->settings->is_debug) { @@ -46,7 +53,6 @@ private function generate_docker_compose() 'services' => [ $this->application->uuid => [ 'image' => "{$this->application->uuid}:TAG", - 'expose' => $this->application->ports_exposes, 'container_name' => $this->application->uuid, 'restart' => 'always', 'labels' => $this->set_labels_for_applications(), @@ -234,12 +240,16 @@ public function deploy() $deploymentUrl = "$currentUrl/deployment/$this->deployment_uuid"; return redirect($deploymentUrl); } - public function cancel() + + public function stop() { + $application = Application::where('uuid', $this->application_uuid)->first(); + $destination = $application->destination->getMorphClass()::where('id', $application->destination->id)->first(); + $command[] = "docker rm -f {$application->uuid} >/dev/null 2>&1"; + remoteProcess($command, $destination->server, null, $application); + } + public function checkStatus() { ContainerStatusJob::dispatch(); } - public function render() - { - return view('livewire.deploy-application'); - } + } diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index 6ece825ea..d5516cdaa 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -46,13 +46,13 @@ public function handle(): void }); $found_application->status = $container['State']; $found_application->save(); - Log::info('Found application: ' . $found_application->uuid . ' settings status to: ' . $found_application->status); + // Log::info('Found application: ' . $found_application->uuid . ' settings status to: ' . $found_application->status); } } foreach ($not_found_applications as $not_found_application) { $not_found_application->status = 'exited'; $not_found_application->save(); - Log::info('Not found application: ' . $not_found_application->uuid . ' settings status to: ' . $not_found_application->status); + // Log::info('Not found application: ' . $not_found_application->uuid . ' settings status to: ' . $not_found_application->status); } } catch (\Exception $e) { Log::error($e->getMessage()); diff --git a/resources/views/livewire/deploy-application.blade.php b/resources/views/livewire/deploy-application.blade.php index 27d01c442..78ae2df99 100644 --- a/resources/views/livewire/deploy-application.blade.php +++ b/resources/views/livewire/deploy-application.blade.php @@ -1,4 +1,5 @@
- + +
diff --git a/resources/views/livewire/poll-activity.blade.php b/resources/views/livewire/poll-activity.blade.php index fc3eeed34..8c69b96de 100644 --- a/resources/views/livewire/poll-activity.blade.php +++ b/resources/views/livewire/poll-activity.blade.php @@ -1,5 +1,5 @@
@isset($activity?->id) -
{{ data_get($activity, 'description') }}
+
{{ data_get($activity, 'description') ?? 'Logs will be here soon...' }}
@endisset
diff --git a/routes/web.php b/routes/web.php index 17e02d287..c2ce8690b 100644 --- a/routes/web.php +++ b/routes/web.php @@ -24,7 +24,7 @@ Route::get('/project/{project_uuid}/{environment_name}', [ProjectController::class, 'resources'])->name('project.resources'); Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}', [ProjectController::class, 'application'])->name('project.application'); - // Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/deployment/{deployment_uuid}', [ProjectController::class, 'deployment'])->name('project.deployment'); + Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/deployment/{deployment_uuid}', [ProjectController::class, 'deployment'])->name('project.deployment'); // Route::get('/database/{database_uuid}', [ProjectController::class, 'database'])->name('project.database'); // Route::get('//service/{service_uuid}', [ProjectController::class, 'service'])->name('project.service'); From 00d998365514fb5bece5e3f1577fb3621b25dc84 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 30 Mar 2023 20:24:11 +0200 Subject: [PATCH 05/12] Add scheduler to supervisod --- app/Console/Kernel.php | 1 - docker/dev/supervisord.conf | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index c38638275..2e89847f0 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -14,7 +14,6 @@ class Kernel extends ConsoleKernel protected function schedule(Schedule $schedule): void { $schedule->job(new ContainerStatusJob)->everyMinute(); - // $schedule->command('inspire')->hourly(); } /** diff --git a/docker/dev/supervisord.conf b/docker/dev/supervisord.conf index a2ff48927..4af5bb4bd 100644 --- a/docker/dev/supervisord.conf +++ b/docker/dev/supervisord.conf @@ -25,3 +25,16 @@ numprocs=8 redirect_stderr=true stdout_logfile=/var/www/html/storage/logs/worker.log stopwaitsecs=3600 + +[program:laravel-schedule] +process_name=%(program_name)s_%(process_num)02d +command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan schedule:work +user=sail +autostart=true +autorestart=true +stopasgroup=true +killasgroup=true +numprocs=8 +redirect_stderr=true +stdout_logfile=/var/www/html/storage/logs/worker.log +stopwaitsecs=3600 From da2deb85c48666db39dc7c60ff4ebe083af5a347 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 30 Mar 2023 21:15:25 +0200 Subject: [PATCH 06/12] wip --- app/Http/Livewire/DeployApplication.php | 16 +++++++++++- app/Jobs/ContainerStatusJob.php | 22 ++++++++-------- app/Models/Project.php | 1 - ...03_27_081716_create_applications_table.php | 2 +- database/seeders/DatabaseSeeder.php | 1 + database/seeders/ServerSettingSeeder.php | 25 +++++++++++++++++++ docker/dev/supervisord.conf | 2 +- 7 files changed, 55 insertions(+), 14 deletions(-) create mode 100644 database/seeders/ServerSettingSeeder.php diff --git a/app/Http/Livewire/DeployApplication.php b/app/Http/Livewire/DeployApplication.php index fac2c305c..82fccd9ad 100644 --- a/app/Http/Livewire/DeployApplication.php +++ b/app/Http/Livewire/DeployApplication.php @@ -7,6 +7,7 @@ use App\Models\CoolifyInstanceSettings; use DateTimeImmutable; use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\Process; use Livewire\Component; use Symfony\Component\Yaml\Yaml; use Visus\Cuid2\Cuid2; @@ -249,7 +250,20 @@ public function stop() remoteProcess($command, $destination->server, null, $application); } public function checkStatus() { - ContainerStatusJob::dispatch(); + $application = Application::where('uuid', $this->application_uuid)->first(); + $destination = $application->destination->getMorphClass()::where('id', $application->destination->id)->first(); + $private_key_location = savePrivateKey($destination->server); + $ssh_command = generateSshCommand($private_key_location, $destination->server->ip, $destination->server->user, $destination->server->port, "docker ps -a --format '{{.State}}' --filter 'name={$application->uuid}'"); + $process = Process::run($ssh_command); + $output = trim($process->output()); + if ($output == '') { + $application->status = 'exited'; + $application->save(); + } else { + $application->status = $output; + $application->save(); + } + // ContainerStatusJob::dispatch(); } } diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index d5516cdaa..2f1fece58 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -11,6 +11,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Process; use Tests\Support\Output; @@ -26,16 +27,17 @@ public function __construct() public function handle(): void { try { - $server = Server::all()->where('settings->is_build_server', '=', false)->first(); + $servers = Server::all()->reject(fn (Server $server) => $server->settings->is_build_server); $applications = Application::all(); $not_found_applications = $applications; - $containers = []; - // foreach ($servers as $server) { - $private_key_location = savePrivateKey($server); - $ssh_command = generateSshCommand($private_key_location, $server->ip, $server->user, $server->port, 'docker ps -a -q --format \'{{json .}}\''); - $process = Process::run($ssh_command); - $output = trim($process->output()); - $containers = formatDockerCmdOutputToJson($output); + $containers = collect(); + foreach ($servers as $server) { + $private_key_location = savePrivateKey($server); + $ssh_command = generateSshCommand($private_key_location, $server->ip, $server->user, $server->port, 'docker ps -a -q --format \'{{json .}}\''); + $process = Process::run($ssh_command); + $output = trim($process->output()); + $containers = $containers->concat(formatDockerCmdOutputToJson($output)); + } foreach ($containers as $container) { $found_application = $applications->filter(function ($value, $key) use ($container) { return $value->uuid == $container['Names']; @@ -46,13 +48,13 @@ public function handle(): void }); $found_application->status = $container['State']; $found_application->save(); - // Log::info('Found application: ' . $found_application->uuid . ' settings status to: ' . $found_application->status); + Log::info('Found application: ' . $found_application->uuid . '.Set status to: ' . $found_application->status); } } foreach ($not_found_applications as $not_found_application) { $not_found_application->status = 'exited'; $not_found_application->save(); - // Log::info('Not found application: ' . $not_found_application->uuid . ' settings status to: ' . $not_found_application->status); + Log::info('Not found application: ' . $not_found_application->uuid . '.Set status to: ' . $not_found_application->status); } } catch (\Exception $e) { Log::error($e->getMessage()); diff --git a/app/Models/Project.php b/app/Models/Project.php index 7dc0ef613..e3f2f105b 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -4,7 +4,6 @@ class Project extends BaseModel { - protected $with = ['settings', 'environments']; protected static function booted() { static::created(function ($project) { diff --git a/database/migrations/2023_03_27_081716_create_applications_table.php b/database/migrations/2023_03_27_081716_create_applications_table.php index 701a70c17..021f8f434 100644 --- a/database/migrations/2023_03_27_081716_create_applications_table.php +++ b/database/migrations/2023_03_27_081716_create_applications_table.php @@ -52,7 +52,7 @@ public function up(): void $table->integer('health_check_retries')->default(10); $table->integer('health_check_start_period')->default(5); - $table->string('status')->default('killed'); + $table->string('status')->default('exited'); $table->morphs('destination'); $table->morphs('source'); diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 00797ca1c..76395f2b0 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -14,6 +14,7 @@ public function run(): void TeamSeeder::class, PrivateKeySeeder::class, ServerSeeder::class, + ServerSettingSeeder::class, ProjectSeeder::class, ProjectSettingSeeder::class, EnvironmentSeeder::class, diff --git a/database/seeders/ServerSettingSeeder.php b/database/seeders/ServerSettingSeeder.php new file mode 100644 index 000000000..a7d5dd97d --- /dev/null +++ b/database/seeders/ServerSettingSeeder.php @@ -0,0 +1,25 @@ +load(['settings']); + $server_1->settings->is_build_server = true; + $server_1->settings->save(); + + $server_2 = Server::find(2)->load(['settings']); + $server_2->settings->is_build_server = true; + $server_2->settings->save(); + + } +} diff --git a/docker/dev/supervisord.conf b/docker/dev/supervisord.conf index 4af5bb4bd..a50aad21c 100644 --- a/docker/dev/supervisord.conf +++ b/docker/dev/supervisord.conf @@ -34,7 +34,7 @@ autostart=true autorestart=true stopasgroup=true killasgroup=true -numprocs=8 +numprocs=1 redirect_stderr=true stdout_logfile=/var/www/html/storage/logs/worker.log stopwaitsecs=3600 From 8cc5276c9debb92ee166d9d5e865dc565d61f510 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 31 Mar 2023 08:36:17 +0200 Subject: [PATCH 07/12] feat: able to control multiplexing --- bootstrap/helpers.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index 64e2fa8b2..892a3cf91 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -62,22 +62,26 @@ function savePrivateKey(Server $server) } if (!function_exists('generateSshCommand')) { - function generateSshCommand(string $private_key_location, string $server_ip, string $user, string $port, $command) + function generateSshCommand(string $private_key_location, string $server_ip, string $user, string $port, string $command, bool $isMux = true) { $delimiter = 'EOF-COOLIFY-SSH'; Storage::disk('local')->makeDirectory('.ssh'); - $ssh_command = "ssh " - . "-i {$private_key_location} " + $ssh_command = "ssh "; + if ($isMux) { + $ssh_command .= '-o ControlMaster=auto -o ControlPersist=1m -o ControlPath=/var/www/html/storage/app/.ssh/ssh_mux_%h_%p_%r '; + } + $ssh_command .= "-i {$private_key_location} " . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' . '-o PasswordAuthentication=no ' . '-o RequestTTY=no ' . '-o LogLevel=ERROR ' - . '-o ControlMaster=auto -o ControlPersist=1m -o ControlPath=/var/www/html/storage/app/.ssh/ssh_mux_%h_%p_%r ' . "-p {$port} " . "{$user}@{$server_ip} " . " 'bash -se' << \\$delimiter" . PHP_EOL . $command . PHP_EOL . $delimiter; + + dd($ssh_command); return $ssh_command; } } @@ -108,7 +112,5 @@ function formatDockerLabelsToJson($rawOutput): Collection return [$outputLine[0] => $outputLine[1]]; }); })[0]; - } } - From e63b15cb677b8ec6c42f38ceba02aa960fbde26e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 31 Mar 2023 08:36:55 +0200 Subject: [PATCH 08/12] fix: remove dd - oops --- bootstrap/helpers.php | 1 - 1 file changed, 1 deletion(-) diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index 892a3cf91..dad126963 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -81,7 +81,6 @@ function generateSshCommand(string $private_key_location, string $server_ip, str . $command . PHP_EOL . $delimiter; - dd($ssh_command); return $ssh_command; } } From 00ae88b6b6f0eeb2056a1a28b5e4350d3d73e632 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 31 Mar 2023 09:41:41 +0200 Subject: [PATCH 09/12] fix: add inprogress activity --- app/Actions/RemoteProcess/RunRemoteProcess.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Actions/RemoteProcess/RunRemoteProcess.php b/app/Actions/RemoteProcess/RunRemoteProcess.php index 038b681a8..fbd62df91 100644 --- a/app/Actions/RemoteProcess/RunRemoteProcess.php +++ b/app/Actions/RemoteProcess/RunRemoteProcess.php @@ -41,6 +41,9 @@ public function __construct(Activity $activity) public function __invoke(): ProcessResult { + $this->activity->properties = $this->activity->properties->merge([ + 'status' => ProcessStatus::IN_PROGRESS, + ]); $this->timeStart = hrtime(true); $processResult = Process::run($this->getCommand(), $this->handleOutput(...)); From 47d3ac3ef546a1807c8376971274ef5484960eae Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 31 Mar 2023 09:42:05 +0200 Subject: [PATCH 10/12] feat: add runRemoteCommandSync --- app/Jobs/ContainerStatusJob.php | 9 +++------ bootstrap/helpers.php | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index 2f1fece58..b3432d3ec 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -32,10 +32,7 @@ public function handle(): void $not_found_applications = $applications; $containers = collect(); foreach ($servers as $server) { - $private_key_location = savePrivateKey($server); - $ssh_command = generateSshCommand($private_key_location, $server->ip, $server->user, $server->port, 'docker ps -a -q --format \'{{json .}}\''); - $process = Process::run($ssh_command); - $output = trim($process->output()); + $output = runRemoteCommandSync($server, ['docker ps -a -q --format \'{{json .}}\'']); $containers = $containers->concat(formatDockerCmdOutputToJson($output)); } foreach ($containers as $container) { @@ -48,13 +45,13 @@ public function handle(): void }); $found_application->status = $container['State']; $found_application->save(); - Log::info('Found application: ' . $found_application->uuid . '.Set status to: ' . $found_application->status); + Log::info('Found application: ' . $found_application->uuid . '. Set status to: ' . $found_application->status); } } foreach ($not_found_applications as $not_found_application) { $not_found_application->status = 'exited'; $not_found_application->save(); - Log::info('Not found application: ' . $not_found_application->uuid . '.Set status to: ' . $not_found_application->status); + Log::info('Not found application: ' . $not_found_application->uuid . '. Set status to: ' . $not_found_application->status); } } catch (\Exception $e) { Log::error($e->getMessage()); diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index dad126963..b613cf109 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Storage; use Spatie\Activitylog\Contracts\Activity; @@ -113,3 +114,18 @@ function formatDockerLabelsToJson($rawOutput): Collection })[0]; } } +if (!function_exists('runRemoteCommandSync')) { + function runRemoteCommandSync($server, array $command) { + $command_string = implode("\n", $command); + $private_key_location = savePrivateKey($server); + $ssh_command = generateSshCommand($private_key_location, $server->ip, $server->user, $server->port, $command_string); + $process = Process::run($ssh_command); + $output = trim($process->output()); + $exitCode = $process->exitCode(); + if ($exitCode !== 0) { + Log::error($output); + throw new \RuntimeException('There was an error running the command.'); + } + return $output; + } +} From e052047b04691ae6c167df39f9d29df0e9f2a619 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 31 Mar 2023 09:42:13 +0200 Subject: [PATCH 11/12] fix: application view --- app/Http/Livewire/DeployApplication.php | 43 ++++++++++--------- .../livewire/deploy-application.blade.php | 1 + resources/views/project/application.blade.php | 5 +-- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/app/Http/Livewire/DeployApplication.php b/app/Http/Livewire/DeployApplication.php index 82fccd9ad..14401a1fc 100644 --- a/app/Http/Livewire/DeployApplication.php +++ b/app/Http/Livewire/DeployApplication.php @@ -21,15 +21,19 @@ class DeployApplication extends Component { public string $application_uuid; public $activity; + public $status; + public Application $application; + public $destination; protected string $deployment_uuid; protected array $command = []; - protected Application $application; - protected $destination; protected $source; - public function mount($application_uuid) { + public function mount($application_uuid) + { $this->application_uuid = $application_uuid; + $this->application = Application::where('uuid', $this->application_uuid)->first(); + $this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first(); } public function render() { @@ -152,7 +156,6 @@ private function generate_jwt_token_for_github() public function deploy() { $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(); $this->source = $this->application->source->getMorphClass()::where('id', $this->application->source->id)->first(); @@ -244,26 +247,24 @@ public function deploy() public function stop() { - $application = Application::where('uuid', $this->application_uuid)->first(); - $destination = $application->destination->getMorphClass()::where('id', $application->destination->id)->first(); - $command[] = "docker rm -f {$application->uuid} >/dev/null 2>&1"; - remoteProcess($command, $destination->server, null, $application); + $output = runRemoteCommandSync($this->destination->server, ["docker rm -f {$this->application_uuid} >/dev/null 2>&1"]); + $this->application->status = 'exited'; + $this->application->save(); + // $this->application->refresh(); } - public function checkStatus() { - $application = Application::where('uuid', $this->application_uuid)->first(); - $destination = $application->destination->getMorphClass()::where('id', $application->destination->id)->first(); - $private_key_location = savePrivateKey($destination->server); - $ssh_command = generateSshCommand($private_key_location, $destination->server->ip, $destination->server->user, $destination->server->port, "docker ps -a --format '{{.State}}' --filter 'name={$application->uuid}'"); - $process = Process::run($ssh_command); - $output = trim($process->output()); + public function pollingStatus() + { + $this->application->refresh(); + } + public function checkStatus() + { + $output = runRemoteCommandSync($this->destination->server, ["docker ps -a --format '{{.State}}' --filter 'name={$this->application->uuid}'"]); if ($output == '') { - $application->status = 'exited'; - $application->save(); + $this->application->status = 'exited'; + $this->application->save(); } else { - $application->status = $output; - $application->save(); + $this->application->status = $output; + $this->application->save(); } - // ContainerStatusJob::dispatch(); } - } diff --git a/resources/views/livewire/deploy-application.blade.php b/resources/views/livewire/deploy-application.blade.php index 78ae2df99..21ba7248e 100644 --- a/resources/views/livewire/deploy-application.blade.php +++ b/resources/views/livewire/deploy-application.blade.php @@ -2,4 +2,5 @@ + status: {{ $application->status }}
diff --git a/resources/views/project/application.blade.php b/resources/views/project/application.blade.php index 4a87abef2..716fb3765 100644 --- a/resources/views/project/application.blade.php +++ b/resources/views/project/application.blade.php @@ -1,15 +1,14 @@

Application

Name: {{ $application->name }}

-

Application UUID: {{ $application->uuid }}

-

Status: {{ $application->status }}

-

Deployments

+

Deployments

@foreach ($deployments as $deployment)

{{ data_get($deployment->properties, 'deployment_uuid') }} + {{ data_get($deployment->properties, 'status') }}

@endforeach
From bb435b082ec040e2cfc6d9d1d90a1c726273b767 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 31 Mar 2023 11:51:04 +0200 Subject: [PATCH 12/12] save --- app/Http/Livewire/DeployApplication.php | 13 ++++++------- docker/builder/Dockerfile | 2 +- resources/views/livewire/poll-activity.blade.php | 3 ++- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/Http/Livewire/DeployApplication.php b/app/Http/Livewire/DeployApplication.php index 14401a1fc..342e2e2f3 100644 --- a/app/Http/Livewire/DeployApplication.php +++ b/app/Http/Livewire/DeployApplication.php @@ -41,11 +41,11 @@ public function render() } private function execute_in_builder(string $command) { - if ($this->application->settings->is_debug) { - return $this->command[] = "docker exec {$this->deployment_uuid} bash -c '{$command}'"; - } else { - return $this->command[] = "docker exec {$this->deployment_uuid} bash -c '{$command}' > /dev/null 2>&1"; - } + return $this->command[] = "docker exec {$this->deployment_uuid} bash -c '{$command}'"; + // if ($this->application->settings->is_debug) { + // } else { + // return $this->command[] = "docker exec {$this->deployment_uuid} bash -c '{$command}'"; + // } } private function start_builder_container() { @@ -247,10 +247,9 @@ public function deploy() public function stop() { - $output = runRemoteCommandSync($this->destination->server, ["docker rm -f {$this->application_uuid} >/dev/null 2>&1"]); + runRemoteCommandSync($this->destination->server, ["docker rm -f {$this->application_uuid} >/dev/null 2>&1"]); $this->application->status = 'exited'; $this->application->save(); - // $this->application->refresh(); } public function pollingStatus() { diff --git a/docker/builder/Dockerfile b/docker/builder/Dockerfile index 32099603b..bbeca59b1 100644 --- a/docker/builder/Dockerfile +++ b/docker/builder/Dockerfile @@ -22,5 +22,5 @@ RUN curl -sSL https://nixpacks.com/install.sh | bash RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack ENTRYPOINT ["/sbin/tini", "--"] -CMD ["sh", "-c", "while true; do sleep 1000; done"] +CMD ["sh", "-c", "while true; do sleep 69420; done"] diff --git a/resources/views/livewire/poll-activity.blade.php b/resources/views/livewire/poll-activity.blade.php index 8c69b96de..389483dc1 100644 --- a/resources/views/livewire/poll-activity.blade.php +++ b/resources/views/livewire/poll-activity.blade.php @@ -1,5 +1,6 @@
@isset($activity?->id) -
{{ data_get($activity, 'description') ?? 'Logs will be here soon...' }}
+
{{ data_get($activity, 'description') }}
@endisset + {{--
{{ data_get($activity, 'properties') }}
--}}