From 9acde06795c31a323cdcc7b5e944a2f8fb9f91b4 Mon Sep 17 00:00:00 2001 From: Piotr Wojcik Date: Sun, 5 Jan 2025 07:47:57 +0100 Subject: [PATCH 1/4] Custom network aliases for Dockerfile and Docker Image apps --- app/Jobs/ApplicationDeploymentJob.php | 7 +++--- app/Livewire/Project/Application/General.php | 2 ++ app/Models/Application.php | 3 +++ ..._network_aliases_to_applications_table.php | 22 +++++++++++++++++++ .../project/application/general.blade.php | 5 +++++ 5 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 database/migrations/2025_01_05_050736_add_network_aliases_to_applications_table.php diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 6b677fa0e..88a836ecc 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1712,9 +1712,10 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue 'expose' => $ports, 'networks' => [ $this->destination->network => [ - 'aliases' => [ - $this->container_name, - ], + 'aliases' => array_merge( + [$this->container_name], + $this->application->network_aliases ? explode(',', $this->application->network_aliases) : [] + ), ], ], 'mem_limit' => $this->application->limits_memory, diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index ff29b74e9..55f7d881e 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -68,6 +68,7 @@ class General extends Component 'application.publish_directory' => 'nullable', 'application.ports_exposes' => 'required', 'application.ports_mappings' => 'nullable', + 'application.network_aliases' => 'nullable', 'application.dockerfile' => 'nullable', 'application.docker_registry_image_name' => 'nullable', 'application.docker_registry_image_tag' => 'nullable', @@ -120,6 +121,7 @@ class General extends Component 'application.custom_labels' => 'Custom labels', 'application.dockerfile_target_build' => 'Dockerfile target build', 'application.custom_docker_run_options' => 'Custom docker run commands', + 'application.custom_network_aliases' => 'Custom docker network aliases', 'application.docker_compose_custom_start_command' => 'Docker compose custom start command', 'application.docker_compose_custom_build_command' => 'Docker compose custom build command', 'application.custom_nginx_configuration' => 'Custom Nginx configuration', diff --git a/app/Models/Application.php b/app/Models/Application.php index bfb2a1041..a0cbe92e7 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -43,6 +43,7 @@ use Visus\Cuid2\Cuid2; 'start_command' => ['type' => 'string', 'description' => 'Start command.'], 'ports_exposes' => ['type' => 'string', 'description' => 'Ports exposes.'], 'ports_mappings' => ['type' => 'string', 'nullable' => true, 'description' => 'Ports mappings.'], + 'network_aliases' => ['type' => 'string', 'nullable' => true, 'description' => 'Network aliases for Docker container.'], 'base_directory' => ['type' => 'string', 'description' => 'Base directory for all commands.'], 'publish_directory' => ['type' => 'string', 'description' => 'Publish directory.'], 'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'], @@ -113,6 +114,8 @@ class Application extends BaseModel protected $appends = ['server_status']; + protected $casts = ['network_aliases' => 'array']; + protected static function booted() { static::addGlobalScope('withRelations', function ($builder) { diff --git a/database/migrations/2025_01_05_050736_add_network_aliases_to_applications_table.php b/database/migrations/2025_01_05_050736_add_network_aliases_to_applications_table.php new file mode 100644 index 000000000..a4e8018a0 --- /dev/null +++ b/database/migrations/2025_01_05_050736_add_network_aliases_to_applications_table.php @@ -0,0 +1,22 @@ +text('network_aliases')->nullable(); + }); + } + + public function down() + { + Schema::table('applications', function (Blueprint $table) { + $table->dropColumn('network_aliases'); + }); + } +}; diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index 4812fd4ba..b5a41f705 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -307,6 +307,11 @@ @endif + @if ($application->build_pack === 'dockerfile' || $application->build_pack === 'dockerimage') + + @endif Date: Tue, 7 Jan 2025 01:59:51 +0100 Subject: [PATCH 2/4] Custom network aliases for other deployment options (not for compose and swarm) --- resources/views/livewire/project/application/general.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index b5a41f705..4c4e03577 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -307,7 +307,7 @@ @endif - @if ($application->build_pack === 'dockerfile' || $application->build_pack === 'dockerimage') + @if (!$application->destination->server->isSwarm()) From fcf597fb1623b87631270ba573075c7d10b88c7f Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 9 Apr 2025 08:33:42 +0200 Subject: [PATCH 3/4] feat(Application): add networkAliases attribute for handling network aliases as JSON or comma-separated values --- app/Jobs/ApplicationDeploymentJob.php | 8 +++- app/Models/Application.php | 60 +++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 9afcbe371..6f0fa2e4b 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1361,7 +1361,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue } } $this->application_deployment_queue->addLogEntry("Preparing container with helper image: $helperImage."); - $this->application_deployment_queue->addLogEntry("Starting graceful shutdown container: {$this->deployment_uuid}"); $this->graceful_shutdown_container($this->deployment_uuid); $this->execute_remote_command( [ @@ -1710,6 +1709,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue ]); $this->application->parseHealthcheckFromDockerfile($this->saved_outputs->get('dockerfile_from_repo')); } + $network_aliases = []; + if (is_array($this->application->network_aliases) && count($this->application->network_aliases) > 0) { + $network_aliases = $this->application->network_aliases; + } + ray($network_aliases); $docker_compose = [ 'services' => [ $this->container_name => [ @@ -1721,7 +1725,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $this->destination->network => [ 'aliases' => array_merge( [$this->container_name], - $this->application->network_aliases ? explode(',', $this->application->network_aliases) : [] + $network_aliases ), ], ], diff --git a/app/Models/Application.php b/app/Models/Application.php index d2c2d97a7..fe7181451 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -118,6 +118,66 @@ class Application extends BaseModel protected $casts = ['network_aliases' => 'array']; + public function networkAliases(): Attribute + { + return Attribute::make( + set: function ($value) { + if (is_null($value) || $value === '') { + return null; + } + + // If it's already a JSON string, decode it + if (is_string($value) && $this->isJson($value)) { + $value = json_decode($value, true); + } + + // If it's a string but not JSON, treat it as a comma-separated list + if (is_string($value) && ! is_array($value)) { + $value = explode(',', $value); + } + + $value = collect($value) + ->map(function ($alias) { + if (is_string($alias)) { + return str_replace(' ', '-', trim($alias)); + } + + return null; + }) + ->filter() + ->unique() // Remove duplicate values + ->values() + ->toArray(); + + return empty($value) ? null : json_encode($value); + }, + get: function ($value) { + if (is_null($value)) { + return null; + } + + if (is_string($value) && $this->isJson($value)) { + return json_decode($value, true); + } + + return is_array($value) ? $value : []; + } + ); + } + + /** + * Check if a string is a valid JSON + */ + private function isJson($string) + { + if (! is_string($string)) { + return false; + } + json_decode($string); + + return json_last_error() === JSON_ERROR_NONE; + } + protected static function booted() { static::addGlobalScope('withRelations', function ($builder) { From 68bd945b09f43c4589c56a39313ee375835fb6f9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 9 Apr 2025 08:42:50 +0200 Subject: [PATCH 4/4] refactor(Application): rename network_aliases to custom_network_aliases across the application for clarity and consistency --- app/Jobs/ApplicationDeploymentJob.php | 11 +++++------ app/Livewire/Project/Application/General.php | 2 +- app/Models/Application.php | 6 +++--- ...0736_add_network_aliases_to_applications_table.php | 4 ++-- .../livewire/project/application/general.blade.php | 4 ++-- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 6f0fa2e4b..6cf642f27 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -329,7 +329,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue } else { $this->write_deployment_configurations(); } - $this->application_deployment_queue->addLogEntry("Starting graceful shutdown container: {$this->deployment_uuid}"); + $this->application_deployment_queue->addLogEntry("Gracefully shutting down build container: {$this->deployment_uuid}"); $this->graceful_shutdown_container($this->deployment_uuid); ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id')); @@ -1709,11 +1709,10 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue ]); $this->application->parseHealthcheckFromDockerfile($this->saved_outputs->get('dockerfile_from_repo')); } - $network_aliases = []; - if (is_array($this->application->network_aliases) && count($this->application->network_aliases) > 0) { - $network_aliases = $this->application->network_aliases; + $custom_network_aliases = []; + if (is_array($this->application->custom_network_aliases) && count($this->application->custom_network_aliases) > 0) { + $custom_network_aliases = $this->application->custom_network_aliases; } - ray($network_aliases); $docker_compose = [ 'services' => [ $this->container_name => [ @@ -1725,7 +1724,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $this->destination->network => [ 'aliases' => array_merge( [$this->container_name], - $network_aliases + $custom_network_aliases ), ], ], diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index bfe0f8387..eaa988b99 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -68,7 +68,7 @@ class General extends Component 'application.publish_directory' => 'nullable', 'application.ports_exposes' => 'required', 'application.ports_mappings' => 'nullable', - 'application.network_aliases' => 'nullable', + 'application.custom_network_aliases' => 'nullable', 'application.dockerfile' => 'nullable', 'application.docker_registry_image_name' => 'nullable', 'application.docker_registry_image_tag' => 'nullable', diff --git a/app/Models/Application.php b/app/Models/Application.php index fe7181451..2feaebf94 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -45,7 +45,7 @@ use Visus\Cuid2\Cuid2; 'start_command' => ['type' => 'string', 'description' => 'Start command.'], 'ports_exposes' => ['type' => 'string', 'description' => 'Ports exposes.'], 'ports_mappings' => ['type' => 'string', 'nullable' => true, 'description' => 'Ports mappings.'], - 'network_aliases' => ['type' => 'string', 'nullable' => true, 'description' => 'Network aliases for Docker container.'], + 'custom_network_aliases' => ['type' => 'string', 'nullable' => true, 'description' => 'Network aliases for Docker container.'], 'base_directory' => ['type' => 'string', 'description' => 'Base directory for all commands.'], 'publish_directory' => ['type' => 'string', 'description' => 'Publish directory.'], 'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'], @@ -116,9 +116,9 @@ class Application extends BaseModel protected $appends = ['server_status']; - protected $casts = ['network_aliases' => 'array']; + protected $casts = ['custom_network_aliases' => 'array']; - public function networkAliases(): Attribute + public function customNetworkAliases(): Attribute { return Attribute::make( set: function ($value) { diff --git a/database/migrations/2025_01_05_050736_add_network_aliases_to_applications_table.php b/database/migrations/2025_01_05_050736_add_network_aliases_to_applications_table.php index a4e8018a0..61fadd0e5 100644 --- a/database/migrations/2025_01_05_050736_add_network_aliases_to_applications_table.php +++ b/database/migrations/2025_01_05_050736_add_network_aliases_to_applications_table.php @@ -9,14 +9,14 @@ return new class extends Migration public function up() { Schema::table('applications', function (Blueprint $table) { - $table->text('network_aliases')->nullable(); + $table->text('custom_network_aliases')->nullable(); }); } public function down() { Schema::table('applications', function (Blueprint $table) { - $table->dropColumn('network_aliases'); + $table->dropColumn('custom_network_aliases'); }); } }; diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index d51dd0257..f971c8a4f 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -343,9 +343,9 @@ helper="A comma separated list of ports you would like to map to the host system. Useful when you do not want to use domains.

Example:
3000:3000,3002:3002

Rolling update is not supported if you have a port mapped to the host." /> @endif @if (!$application->destination->server->isSwarm()) - + wire:model="application.custom_network_aliases" /> @endif