From c3e2a741ea84c49f8472c0e3b1fbc14ce652bf11 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 29 Jan 2024 20:35:35 +0100 Subject: [PATCH 01/13] Update version numbers --- 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 4e79f8e6a..050405d5e 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.202', + 'release' => '4.0.0-beta.203', // 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 e8285e73e..c1ca7dc2b 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ Date: Tue, 30 Jan 2024 08:26:33 +0100 Subject: [PATCH 02/13] fix: service deletion fix --- app/Actions/Service/DeleteService.php | 63 +++++++++++++++------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/app/Actions/Service/DeleteService.php b/app/Actions/Service/DeleteService.php index 743158c2d..a70adfecf 100644 --- a/app/Actions/Service/DeleteService.php +++ b/app/Actions/Service/DeleteService.php @@ -10,36 +10,43 @@ class DeleteService use AsAction; public function handle(Service $service) { - $server = data_get($service, 'server'); - if ($server->isFunctional()) { - StopService::run($service); - } - $storagesToDelete = collect([]); + try { + $server = data_get($service, 'server'); + if ($server->isFunctional()) { + StopService::run($service); + $storagesToDelete = collect([]); - $service->environment_variables()->delete(); - $commands = []; - foreach ($service->applications()->get() as $application) { - $storages = $application->persistentStorages()->get(); - foreach ($storages as $storage) { - $storagesToDelete->push($storage); - } - $application->forceDelete(); - } - foreach ($service->databases()->get() as $database) { - $storages = $database->persistentStorages()->get(); - foreach ($storages as $storage) { - $storagesToDelete->push($storage); - } - $database->forceDelete(); - } - if ($server->isFunctional()) { - foreach ($storagesToDelete as $storage) { - $commands[] = "docker volume rm -f $storage->name"; - } - $commands[] = "docker rm -f $service->uuid"; + $service->environment_variables()->delete(); + $commands = []; + foreach ($service->applications()->get() as $application) { + $storages = $application->persistentStorages()->get(); + foreach ($storages as $storage) { + $storagesToDelete->push($storage); + } + } + foreach ($service->databases()->get() as $database) { + $storages = $database->persistentStorages()->get(); + foreach ($storages as $storage) { + $storagesToDelete->push($storage); + } + } + foreach ($storagesToDelete as $storage) { + $commands[] = "docker volume rm -f $storage->name"; + } + $commands[] = "docker rm -f $service->uuid"; - instant_remote_process($commands, $server, false); + instant_remote_process($commands, $server, false); + } + } catch (\Exception $e) { + throw new \Exception($e->getMessage()); + } finally { + foreach ($service->applications()->get() as $application) { + $application->forceDelete(); + } + foreach ($service->databases()->get() as $database) { + $database->forceDelete(); + } + $service->forceDelete(); } - $service->forceDelete(); } } From 3ae95018141c1fd50b8afe53d031098a068af490 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 30 Jan 2024 09:22:34 +0100 Subject: [PATCH 03/13] fix: dns validation + duplicated fqdns --- app/Livewire/Project/Application/General.php | 3 +- app/Livewire/Project/Service/Application.php | 1 + app/Models/Application.php | 8 ++++++ app/Models/ServiceApplication.php | 1 - bootstrap/helpers/shared.php | 30 ++++++++++++++++++++ resources/views/components/toast.blade.php | 10 +++---- 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index 23bd94fb2..0f6d61957 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -245,9 +245,10 @@ class General extends Component $domains = $domains->unique(); foreach ($domains as $domain) { if (!validate_dns_entry($domain, $this->application->destination->server)) { - $showToaster && $this->dispatch('error', "Validating DNS settings for: $domain failed.
Make sure you have added the DNS records correctly.

Check this documentation for further help."); + $showToaster && $this->dispatch('error', "Validating DNS ($domain) failed.","Make sure you have added the DNS records correctly.

Check this documentation for further help."); } } + check_fqdn_usage($this->application); $this->application->fqdn = $domains->implode(','); } diff --git a/app/Livewire/Project/Service/Application.php b/app/Livewire/Project/Service/Application.php index 3ff711400..c3157921b 100644 --- a/app/Livewire/Project/Service/Application.php +++ b/app/Livewire/Project/Service/Application.php @@ -53,6 +53,7 @@ class Application extends Component public function submit() { try { + check_fqdn_usage($this->application); $this->validate(); $this->application->save(); updateCompose($this->application); diff --git a/app/Models/Application.php b/app/Models/Application.php index 9e9626ec2..e6b3309f1 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -1116,4 +1116,12 @@ class Application extends BaseModel $this->save(); return $customLabels; } + public function fqdns(): Attribute + { + return Attribute::make( + get: fn () => is_null($this->fqdn) + ? [] + : explode(',', $this->fqdn), + ); + } } diff --git a/app/Models/ServiceApplication.php b/app/Models/ServiceApplication.php index 510395266..dff791da1 100644 --- a/app/Models/ServiceApplication.php +++ b/app/Models/ServiceApplication.php @@ -55,7 +55,6 @@ class ServiceApplication extends BaseModel get: fn () => is_null($this->fqdn) ? [] : explode(',', $this->fqdn), - ); } public function getFilesFromServer(bool $isInit = false) diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 3cff9ba24..5123d8510 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -1660,3 +1660,33 @@ function ip_match($ip, $cidrs, &$match = null) } return false; } +function check_fqdn_usage(ServiceApplication|Application $own_resource) +{ + $domains = collect($own_resource->fqdns)->map(function ($domain) { + return Url::fromString($domain)->getHost(); + }); + $apps = Application::all(); + foreach ($apps as $app) { + $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== ''); + foreach ($list_of_domains as $domain) { + $naked_domain = Url::fromString($domain)->getHost(); + if ($domains->contains($naked_domain)) { + if ($app->uuid !== $own_resource->uuid ) { + throw new \RuntimeException("Domain $naked_domain is already in use by another resource."); + } + } + } + } + $apps = ServiceApplication::all(); + foreach ($apps as $app) { + $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== ''); + foreach ($list_of_domains as $domain) { + $naked_domain = Url::fromString($domain)->getHost(); + if ($domains->contains($naked_domain)) { + if ($app->uuid !== $own_resource->uuid) { + throw new \RuntimeException("Domain $naked_domain is already in use by another resource."); + } + } + } + } +} diff --git a/resources/views/components/toast.blade.php b/resources/views/components/toast.blade.php index 90cdb26e8..f28bbc5eb 100644 --- a/resources/views/components/toast.blade.php +++ b/resources/views/components/toast.blade.php @@ -369,14 +369,14 @@ window.customToastHTML = ` }, 5); }, 4000);" @mouseover="toastHovered=true" @mouseout="toastHovered=false" - class="absolute w-full duration-300 ease-out select-none sm:max-w-xs" + class="absolute w-full duration-200 ease-out select-none sm:max-w-xs" :class="{ 'toast-no-description': !toast.description }">