From 34febe670da6ced116f259866cd0202164d93e40 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 11 Jan 2024 14:13:43 +0100 Subject: [PATCH 01/13] fix: load profile on remote commands --- app/Livewire/Project/Shared/ExecuteContainerCommand.php | 4 ++-- config/sentry.php | 2 +- config/version.php | 2 +- versions.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/Livewire/Project/Shared/ExecuteContainerCommand.php b/app/Livewire/Project/Shared/ExecuteContainerCommand.php index f06f7784d..c92db28b4 100644 --- a/app/Livewire/Project/Shared/ExecuteContainerCommand.php +++ b/app/Livewire/Project/Shared/ExecuteContainerCommand.php @@ -108,8 +108,8 @@ class ExecuteContainerCommand extends Component $this->validate(); try { // Wrap command to prevent escaped execution in the host. - $cmd = 'sh -c "' . str_replace('"', '\"', $this->command) . '"'; - + $cmd = 'sh -c "if [ -f ~/.profile ]; then . ~/.profile; fi; ' . str_replace('"', '\"', $this->command) . '"'; + ray($cmd); if (!empty($this->workDir)) { $exec = "docker exec -w {$this->workDir} {$this->container} {$cmd}"; } else { diff --git a/config/sentry.php b/config/sentry.php index c586dba82..e793c9f2b 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -7,7 +7,7 @@ return [ // The release version of your application // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) - 'release' => '4.0.0-beta.187', + 'release' => '4.0.0-beta.188', // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/version.php b/config/version.php index 8dc7a5d2f..d91322b99 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ Date: Thu, 11 Jan 2024 14:24:54 +0100 Subject: [PATCH 02/13] cleanup --- resources/views/command-center.blade.php | 12 ---- resources/views/profile.blade.php | 83 ------------------------ 2 files changed, 95 deletions(-) delete mode 100644 resources/views/command-center.blade.php delete mode 100644 resources/views/profile.blade.php diff --git a/resources/views/command-center.blade.php b/resources/views/command-center.blade.php deleted file mode 100644 index 33474eac6..000000000 --- a/resources/views/command-center.blade.php +++ /dev/null @@ -1,12 +0,0 @@ - -

Command Center

-
Execute commands on your servers without leaving the browser.
- @if ($servers->count() > 0) - - @else -
-
No servers found. Without a server, you won't be able to do much.
- -
- @endif -
diff --git a/resources/views/profile.blade.php b/resources/views/profile.blade.php deleted file mode 100644 index 9ad4d347f..000000000 --- a/resources/views/profile.blade.php +++ /dev/null @@ -1,83 +0,0 @@ - -

Profile

-
Your user profile settings.
- -

Subscription

- Check in Team Settings -

Two-factor Authentication

- @if (session('status') == 'two-factor-authentication-enabled') -
- Please finish configuring two factor authentication below. Read the QR code or enter the secret key - manually. -
-
-
- @csrf - - Validate 2FA - -
-
{!! $request->user()->twoFactorQrCodeSvg() !!}
-
- - Show secret key to manually - enter -
-
-
- @elseif(session('status') == 'two-factor-authentication-confirmed') -
- Two factor authentication confirmed and enabled successfully. -
-
-
Here are the recovery codes for your account. Please store them in a secure - location. -
-
- @foreach ($request->user()->recoveryCodes() as $code) -
{{ $code }}
- @endforeach -
-
- @else - @if ($request->user()->two_factor_confirmed_at) -
Two factor authentication is enabled.
-
-
- @csrf - @method ('DELETE') - Disable -
-
- @csrf - Regenerate Recovery Codes -
-
- @if (session('status') == 'recovery-codes-generated') -
-
Here are the recovery codes for your account. Please store them in a - secure - location. -
-
- @foreach ($request->user()->recoveryCodes() as $code) -
{{ $code }}
- @endforeach -
-
- @endif - @else -
- @csrf - Configure 2FA -
- @endif - @endif - @if (session()->has('errors')) -
- Something went wrong. Please try again. -
- @endif -
From efa5dd28f19998aace3ee0517fb3ee7c0e345003 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 11 Jan 2024 14:25:42 +0100 Subject: [PATCH 03/13] fix: load profile and set envs on remote cmd --- bootstrap/helpers/remoteProcess.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/helpers/remoteProcess.php b/bootstrap/helpers/remoteProcess.php index f49c7cafc..da6705e4c 100644 --- a/bootstrap/helpers/remoteProcess.php +++ b/bootstrap/helpers/remoteProcess.php @@ -126,7 +126,7 @@ function generateSshCommand(Server $server, string $command, bool $isMux = true) if (data_get($server, 'settings.is_cloudflare_tunnel')) { $ssh_command .= '-o ProxyCommand="/usr/local/bin/cloudflared access ssh --hostname %h" '; } - $command = "PATH=\$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/host/usr/local/sbin:/host/usr/local/bin:/host/usr/sbin:/host/usr/bin:/host/sbin:/host/bin && $command"; + $command = "test -f ~/.profile && . ~/.profile; PATH=\$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/host/usr/local/sbin:/host/usr/local/bin:/host/usr/sbin:/host/usr/bin:/host/sbin:/host/bin && $command"; $ssh_command .= "-i {$privateKeyLocation} " . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' . '-o PasswordAuthentication=no ' From cc1fb83c793edcb82a75807b258df35594c47c19 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 11 Jan 2024 14:25:55 +0100 Subject: [PATCH 04/13] cleanup --- app/Jobs/ApplicationDeploymentJob.php | 4 ---- app/Livewire/Project/Shared/ExecuteContainerCommand.php | 1 - 2 files changed, 5 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index b7534952c..80bc509be 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -744,7 +744,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->build_image(); $this->stop_running_container(); if ($this->application->destination->server->isSwarm()) { - ray("{$this->workdir}{$this->docker_compose_location}"); $this->push_to_docker_registry(); $this->execute_remote_command( [ @@ -911,10 +910,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted if ($this->nixpacks_plan) { $parsed = Toml::Parse($this->nixpacks_plan); // Do any modifications here - // $cmds = collect(data_get($parsed, 'phases.setup.cmds', [])); $this->generate_env_variables(); - // data_set($parsed, 'phases.setup.cmds', $cmds); - ray($this->env_args->toArray()); $merged_envs = $this->env_args->merge(collect(data_get($parsed, 'variables', []))); data_set($parsed, 'variables', $merged_envs->toArray()); $this->nixpacks_plan = json_encode($parsed, JSON_PRETTY_PRINT); diff --git a/app/Livewire/Project/Shared/ExecuteContainerCommand.php b/app/Livewire/Project/Shared/ExecuteContainerCommand.php index c92db28b4..1ffcd810b 100644 --- a/app/Livewire/Project/Shared/ExecuteContainerCommand.php +++ b/app/Livewire/Project/Shared/ExecuteContainerCommand.php @@ -109,7 +109,6 @@ class ExecuteContainerCommand extends Component try { // Wrap command to prevent escaped execution in the host. $cmd = 'sh -c "if [ -f ~/.profile ]; then . ~/.profile; fi; ' . str_replace('"', '\"', $this->command) . '"'; - ray($cmd); if (!empty($this->workDir)) { $exec = "docker exec -w {$this->workDir} {$this->container} {$cmd}"; } else { From 3a391b69e85a7bc6cad092be0899c3a01cf33f62 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 11 Jan 2024 14:34:48 +0100 Subject: [PATCH 05/13] fix: restart should not update config hash --- app/Jobs/ApplicationDeploymentJob.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 80bc509be..9043446a0 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -203,7 +203,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted dispatch(new ContainerStatusJob($this->server)); } $this->next(ApplicationDeploymentStatus::FINISHED->value); - $this->application->isConfigurationChanged(true); + $this->application->isConfigurationChanged(false); return; } else if ($this->application->dockerfile) { $this->deploy_simple_dockerfile(); From a2f53085e58c6503fae1aab615399f4b5689a007 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 12 Jan 2024 08:38:08 +0100 Subject: [PATCH 06/13] fix: preview deployments with nixpacks --- app/Jobs/ApplicationDeploymentJob.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 9043446a0..e846f9f61 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -738,9 +738,12 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->generate_nixpacks_confs(); } $this->generate_compose_file(); + // Needs separate preview variables $this->generate_build_env_variables(); - $this->add_build_env_variables_to_dockerfile(); + if ($this->application->build_pack !== 'nixpacks') { + $this->add_build_env_variables_to_dockerfile(); + } $this->build_image(); $this->stop_running_container(); if ($this->application->destination->server->isSwarm()) { From 79e0df1d4349218b4500d96a3753c9ea79a6c556 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 12 Jan 2024 08:45:24 +0100 Subject: [PATCH 07/13] fix: cleanup docker stuffs before upgrading --- app/Actions/Server/CleanupDocker.php | 23 +++++++++++++++++++++++ app/Actions/Server/UpdateCoolify.php | 1 + app/Jobs/DockerCleanupJob.php | 5 ++--- 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 app/Actions/Server/CleanupDocker.php diff --git a/app/Actions/Server/CleanupDocker.php b/app/Actions/Server/CleanupDocker.php new file mode 100644 index 000000000..4faeccf1a --- /dev/null +++ b/app/Actions/Server/CleanupDocker.php @@ -0,0 +1,23 @@ +server) { return; } + CleanupDocker::run($this->server, false); $this->latestVersion = get_latest_version_of_coolify(); $this->currentVersion = config('version'); ray('latest version:' . $this->latestVersion . " current version: " . $this->currentVersion . ' force: ' . $force); diff --git a/app/Jobs/DockerCleanupJob.php b/app/Jobs/DockerCleanupJob.php index a48ddd248..69c445801 100644 --- a/app/Jobs/DockerCleanupJob.php +++ b/app/Jobs/DockerCleanupJob.php @@ -2,6 +2,7 @@ namespace App\Jobs; +use App\Actions\Server\CleanupDocker; use App\Models\Server; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeEncrypted; @@ -43,9 +44,7 @@ class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted ray('Usage before: ' . $this->usageBefore); if ($this->usageBefore >= $this->server->settings->cleanup_after_percentage) { ray('Cleaning up ' . $this->server->name); - instant_remote_process(['docker image prune -af'], $this->server, false); - instant_remote_process(['docker container prune -f --filter "label=coolify.managed=true"'], $this->server, false); - instant_remote_process(['docker builder prune -af'], $this->server, false); + CleanupDocker::run($this->server); $usageAfter = $this->server->getDiskUsage(); if ($usageAfter < $this->usageBefore) { ray('Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name); From 18ad7220f0c34b6210400dc9131a61312e4aba9f Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 12 Jan 2024 08:49:03 +0100 Subject: [PATCH 08/13] 10 mins server check -> 5 mins --- app/Console/Kernel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 267572b39..7dbead831 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -72,7 +72,7 @@ class Kernel extends ConsoleKernel } } foreach ($servers as $server) { - $schedule->job(new ServerStatusJob($server))->everyTenMinutes()->onOneServer(); + $schedule->job(new ServerStatusJob($server))->everyFiveMinutes()->onOneServer(); } } private function instance_auto_update($schedule) From f61210287ea59be71ff291e676f60ef0c89cf527 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 12 Jan 2024 08:56:59 +0100 Subject: [PATCH 09/13] Update release version to 4.0.0-beta.189 --- config/sentry.php | 2 +- config/version.php | 2 +- versions.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/sentry.php b/config/sentry.php index e793c9f2b..2d526fb85 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -7,7 +7,7 @@ return [ // The release version of your application // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) - 'release' => '4.0.0-beta.188', + 'release' => '4.0.0-beta.189', // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/version.php b/config/version.php index d91322b99..dec4e2c54 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ Date: Fri, 12 Jan 2024 09:11:36 +0100 Subject: [PATCH 10/13] fix: service deletion command --- app/Console/Commands/ServicesDelete.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Console/Commands/ServicesDelete.php b/app/Console/Commands/ServicesDelete.php index 31ccfa9a9..bc30bd842 100644 --- a/app/Console/Commands/ServicesDelete.php +++ b/app/Console/Commands/ServicesDelete.php @@ -2,6 +2,7 @@ namespace App\Console\Commands; +use App\Jobs\DeleteResourceJob; use App\Models\Application; use App\Models\Server; use App\Models\Service; @@ -91,7 +92,7 @@ class ServicesDelete extends Command if (!$confirmed) { break; } - $toDelete->delete(); + DeleteResourceJob::dispatch($toDelete); } } } @@ -115,7 +116,7 @@ class ServicesDelete extends Command if (!$confirmed) { return; } - $toDelete->delete(); + DeleteResourceJob::dispatch($toDelete); } } } @@ -139,7 +140,7 @@ class ServicesDelete extends Command if (!$confirmed) { return; } - $toDelete->delete(); + DeleteResourceJob::dispatch($toDelete); } } } From 8d04fbdb74b55b4fa6a8ea0459e77ea079963291 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 12 Jan 2024 11:25:20 +0100 Subject: [PATCH 11/13] feat: search between resources --- app/Livewire/Project/Resource/Index.php | 87 ++++++- resources/css/app.css | 2 +- .../livewire/project/resource/index.blade.php | 232 ++++++++++++++---- 3 files changed, 270 insertions(+), 51 deletions(-) diff --git a/app/Livewire/Project/Resource/Index.php b/app/Livewire/Project/Resource/Index.php index 2a7570c9d..6a170ace8 100644 --- a/app/Livewire/Project/Resource/Index.php +++ b/app/Livewire/Project/Resource/Index.php @@ -10,7 +10,15 @@ class Index extends Component { public Project $project; public Environment $environment; - public function mount () { + public $applications = []; + public $postgresqls = []; + public $redis = []; + public $mongodbs = []; + public $mysqls = []; + public $mariadbs = []; + public $services = []; + public function mount() + { $project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); if (!$project) { return redirect()->route('dashboard'); @@ -21,6 +29,83 @@ class Index extends Component } $this->project = $project; $this->environment = $environment; + $this->applications = $environment->applications->sortBy('name'); + $this->applications = $this->applications->map(function ($application) { + if (data_get($application, 'environment.project.uuid')) { + $application->hrefLink = route('project.application.configuration', [ + 'project_uuid' => data_get($application, 'environment.project.uuid'), + 'environment_name' => data_get($application, 'environment.name'), + 'application_uuid' => data_get($application, 'uuid') + ]); + } + return $application; + }); + $this->postgresqls = $environment->postgresqls->sortBy('name'); + $this->postgresqls = $this->postgresqls->map(function ($postgresql) { + if (data_get($postgresql, 'environment.project.uuid')) { + $postgresql->hrefLink = route('project.database.configuration', [ + 'project_uuid' => data_get($postgresql, 'environment.project.uuid'), + 'environment_name' => data_get($postgresql, 'environment.name'), + 'database_uuid' => data_get($postgresql, 'uuid') + ]); + } + return $postgresql; + }); + $this->redis = $environment->redis->sortBy('name'); + $this->redis = $this->redis->map(function ($redis) { + if (data_get($redis, 'environment.project.uuid')) { + $redis->hrefLink = route('project.database.configuration', [ + 'project_uuid' => data_get($redis, 'environment.project.uuid'), + 'environment_name' => data_get($redis, 'environment.name'), + 'database_uuid' => data_get($redis, 'uuid') + ]); + } + return $redis; + }); + $this->mongodbs = $environment->mongodbs->sortBy('name'); + $this->mongodbs = $this->mongodbs->map(function ($mongodb) { + if (data_get($mongodb, 'environment.project.uuid')) { + $mongodb->hrefLink = route('project.database.configuration', [ + 'project_uuid' => data_get($mongodb, 'environment.project.uuid'), + 'environment_name' => data_get($mongodb, 'environment.name'), + 'database_uuid' => data_get($mongodb, 'uuid') + ]); + } + return $mongodb; + }); + $this->mysqls = $environment->mysqls->sortBy('name'); + $this->mysqls = $this->mysqls->map(function ($mysql) { + if (data_get($mysql, 'environment.project.uuid')) { + $mysql->hrefLink = route('project.database.configuration', [ + 'project_uuid' => data_get($mysql, 'environment.project.uuid'), + 'environment_name' => data_get($mysql, 'environment.name'), + 'database_uuid' => data_get($mysql, 'uuid') + ]); + } + return $mysql; + }); + $this->mariadbs = $environment->mariadbs->sortBy('name'); + $this->mariadbs = $this->mariadbs->map(function ($mariadb) { + if (data_get($mariadb, 'environment.project.uuid')) { + $mariadb->hrefLink = route('project.database.configuration', [ + 'project_uuid' => data_get($mariadb, 'environment.project.uuid'), + 'environment_name' => data_get($mariadb, 'environment.name'), + 'database_uuid' => data_get($mariadb, 'uuid') + ]); + } + return $mariadb; + }); + $this->services = $environment->services->sortBy('name'); + $this->services = $this->services->map(function ($service) { + if (data_get($service, 'environment.project.uuid')) { + $service->hrefLink = route('project.service.configuration', [ + 'project_uuid' => data_get($service, 'environment.project.uuid'), + 'environment_name' => data_get($service, 'environment.name'), + 'service_uuid' => data_get($service, 'uuid') + ]); + } + return $service; + }); } public function render() { diff --git a/resources/css/app.css b/resources/css/app.css index 868cbd9c0..cd383c1cd 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -80,7 +80,7 @@ a { } .description { - @apply pt-2 text-xs font-bold text-neutral-500 group-hover:text-white; + @apply text-xs font-bold text-neutral-500 group-hover:text-white; } .lds-heart { diff --git a/resources/views/livewire/project/resource/index.blade.php b/resources/views/livewire/project/resource/index.blade.php index a1ff05693..ca2325419 100644 --- a/resources/views/livewire/project/resource/index.blade.php +++ b/resources/views/livewire/project/resource/index.blade.php @@ -44,54 +44,188 @@ + Add New Resource @endif - + + From 408738e08def21a1ae99781c345997d827000b91 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 12 Jan 2024 11:31:51 +0100 Subject: [PATCH 12/13] Add service status to Index.php and update resource display in index.blade.php --- app/Livewire/Project/Resource/Index.php | 1 + .../livewire/project/resource/index.blade.php | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/app/Livewire/Project/Resource/Index.php b/app/Livewire/Project/Resource/Index.php index 6a170ace8..718b5003c 100644 --- a/app/Livewire/Project/Resource/Index.php +++ b/app/Livewire/Project/Resource/Index.php @@ -103,6 +103,7 @@ class Index extends Component 'environment_name' => data_get($service, 'environment.name'), 'service_uuid' => data_get($service, 'uuid') ]); + $service->status = serviceStatus($service); } return $service; }); diff --git a/resources/views/livewire/project/resource/index.blade.php b/resources/views/livewire/project/resource/index.blade.php index ca2325419..921e9c360 100644 --- a/resources/views/livewire/project/resource/index.blade.php +++ b/resources/views/livewire/project/resource/index.blade.php @@ -150,6 +150,23 @@ + @@ -164,6 +181,7 @@ mongodbs: @js($mongodbs), mysqls: @js($mysqls), mariadbs: @js($mariadbs), + services: @js($services), get filteredApplications() { if (this.search === '') { return this.applications; @@ -225,6 +243,16 @@ item.description?.toLowerCase().includes(this.search.toLowerCase()); }); }, + get filteredServices() { + if (this.search === '') { + return this.services; + } + this.services = Object.values(this.services); + return this.services.filter(item => { + return item.name.toLowerCase().includes(this.search.toLowerCase()) || + item.description?.toLowerCase().includes(this.search.toLowerCase()); + }); + }, }; } From f1298d1db4ea6357f345abb5957c5bcb8489f911 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 12 Jan 2024 12:44:08 +0100 Subject: [PATCH 13/13] do not send notification of scheduled task failed --- app/Jobs/ScheduledTaskJob.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Jobs/ScheduledTaskJob.php b/app/Jobs/ScheduledTaskJob.php index 104b5f7e3..49511ad95 100644 --- a/app/Jobs/ScheduledTaskJob.php +++ b/app/Jobs/ScheduledTaskJob.php @@ -108,7 +108,7 @@ class ScheduledTaskJob implements ShouldQueue 'message' => $this->task_output ?? $e->getMessage(), ]); } - send_internal_notification('ScheduledTaskJob failed with: ' . $e->getMessage()); + // send_internal_notification('ScheduledTaskJob failed with: ' . $e->getMessage()); throw $e; } }