diff --git a/app/Http/Livewire/Project/Application/General.php b/app/Http/Livewire/Project/Application/General.php index dc3bd8db6..810c7cc42 100644 --- a/app/Http/Livewire/Project/Application/General.php +++ b/app/Http/Livewire/Project/Application/General.php @@ -3,12 +3,9 @@ namespace App\Http\Livewire\Project\Application; use App\Models\Application; -use App\Models\InstanceSettings; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Livewire\Component; -use Spatie\Url\Url; -use Symfony\Component\Yaml\Yaml; class General extends Component { @@ -23,6 +20,9 @@ class General extends Component public ?string $git_commit_sha = null; public string $build_pack; + public $customLabels; + public bool $labelsChanged = false; + public bool $is_static; public bool $is_git_submodules_enabled; public bool $is_git_lfs_enabled; @@ -52,6 +52,7 @@ class General extends Component 'application.docker_registry_image_name' => 'nullable', 'application.docker_registry_image_tag' => 'nullable', 'application.dockerfile_location' => 'nullable', + 'application.custom_labels' => 'nullable', ]; protected $validationAttributes = [ 'application.name' => 'name', @@ -73,16 +74,43 @@ class General extends Component 'application.docker_registry_image_name' => 'Docker registry image name', 'application.docker_registry_image_tag' => 'Docker registry image tag', 'application.dockerfile_location' => 'Dockerfile location', - + 'application.custom_labels' => 'Custom labels', ]; - public function updatedApplicationBuildPack(){ + public function mount() + { + if (is_null(data_get($this->application, 'custom_labels'))) { + $this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n"); + } else { + $this->customLabels = str($this->application->custom_labels)->replace(',', "\n"); + } + if (data_get($this->application, 'settings')) { + $this->is_static = $this->application->settings->is_static; + $this->is_git_submodules_enabled = $this->application->settings->is_git_submodules_enabled; + $this->is_git_lfs_enabled = $this->application->settings->is_git_lfs_enabled; + $this->is_debug_enabled = $this->application->settings->is_debug_enabled; + $this->is_preview_deployments_enabled = $this->application->settings->is_preview_deployments_enabled; + $this->is_auto_deploy_enabled = $this->application->settings->is_auto_deploy_enabled; + $this->is_force_https_enabled = $this->application->settings->is_force_https_enabled; + } + $this->checkLabelUpdates(); + } + public function updatedApplicationBuildPack() + { if ($this->application->build_pack !== 'nixpacks') { $this->application->settings->is_static = $this->is_static = false; $this->application->settings->save(); } $this->submit(); } + public function checkLabelUpdates() + { + if (md5($this->application->custom_labels) !== md5(implode(",", generateLabelsApplication($this->application)))) { + $this->labelsChanged = true; + } else { + $this->labelsChanged = false; + } + } public function instantSave() { // @TODO: find another way - if possible @@ -102,37 +130,35 @@ class General extends Component $this->application->save(); $this->application->refresh(); $this->emit('success', 'Application settings updated!'); + $this->checkLabelUpdates(); } - public function getWildcardDomain() { + public function getWildcardDomain() + { $server = data_get($this->application, 'destination.server'); if ($server) { $fqdn = generateFqdn($server, $this->application->uuid); - ray($fqdn); $this->application->fqdn = $fqdn; $this->application->save(); $this->emit('success', 'Application settings updated!'); } - } - public function mount() + public function resetDefaultLabels($showToaster = true) { - if (data_get($this->application,'settings')) { - $this->is_static = $this->application->settings->is_static; - $this->is_git_submodules_enabled = $this->application->settings->is_git_submodules_enabled; - $this->is_git_lfs_enabled = $this->application->settings->is_git_lfs_enabled; - $this->is_debug_enabled = $this->application->settings->is_debug_enabled; - $this->is_preview_deployments_enabled = $this->application->settings->is_preview_deployments_enabled; - $this->is_auto_deploy_enabled = $this->application->settings->is_auto_deploy_enabled; - $this->is_force_https_enabled = $this->application->settings->is_force_https_enabled; - } + $this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n"); + $this->submit($showToaster); } - public function submit() + public function updatedApplicationFqdn() + { + $this->resetDefaultLabels(false); + $this->emit('success', 'Labels reseted to default!'); + } + public function submit($showToaster = true) { try { $this->validate(); - if (data_get($this->application,'build_pack') === 'dockerimage') { + if (data_get($this->application, 'build_pack') === 'dockerimage') { $this->validate([ 'application.docker_registry_image_name' => 'required', 'application.docker_registry_image_tag' => 'required', @@ -156,10 +182,16 @@ class General extends Component if ($this->application->publish_directory && $this->application->publish_directory !== '/') { $this->application->publish_directory = rtrim($this->application->publish_directory, '/'); } + if (gettype($this->customLabels) === 'string') { + $this->customLabels = str($this->customLabels)->replace(',', "\n"); + } + $this->application->custom_labels = $this->customLabels->explode("\n")->implode(','); $this->application->save(); - $this->emit('success', 'Application settings updated!'); + $showToaster && $this->emit('success', 'Application settings updated!'); } catch (\Throwable $e) { return handleError($e, $this); + } finally { + $this->checkLabelUpdates(); } } } diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 09e7c510d..636adb35a 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -54,7 +54,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted private ApplicationPreview|null $preview = null; private string $container_name; - private string|null $currently_running_container_name = null; + private ?string $currently_running_container_name = null; private string $basedir; private string $workdir; private ?string $build_pack = null; @@ -166,7 +166,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted // Get user home directory $this->serverUserHomeDir = instant_remote_process(["echo \$HOME"], $this->server); - ray("test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'"); $this->dockerConfigFileExists = instant_remote_process(["test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'"], $this->server); try { if ($this->application->dockerfile) { @@ -650,6 +649,10 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $volume_names = $this->generate_local_persistent_volumes_only_volume_names(); $environment_variables = $this->generate_environment_variables($ports); + $labels = generateLabelsApplication($this->application, $this->preview); + if (data_get($this->application, 'custom_labels')) { + $labels = str($this->application->custom_labels)->explode(',')->toArray(); + } $docker_compose = [ 'version' => '3.8', 'services' => [ @@ -658,7 +661,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted 'container_name' => $this->container_name, 'restart' => RESTART_MODE, 'environment' => $environment_variables, - 'labels' => generateLabelsApplication($this->application, $this->preview, $ports), + 'labels' => $labels, 'expose' => $ports, 'networks' => [ $this->destination->network, diff --git a/app/Models/Service.php b/app/Models/Service.php index 4fbb6a1f7..95fe826fb 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -538,7 +538,7 @@ class Service extends BaseModel $serviceLabels = $serviceLabels->merge($defaultLabels); if (!$isDatabase && $fqdns->count() > 0) { if ($fqdns) { - $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($fqdns, true)); + $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($this->uuid, $fqdns, true)); } } data_set($service, 'labels', $serviceLabels->toArray()); @@ -568,7 +568,7 @@ class Service extends BaseModel 'networks' => $topLevelNetworks->toArray(), ]; $this->docker_compose_raw = Yaml::dump($yaml, 10, 2); - $this->docker_compose = Yaml::dump($finalServices, 10, 2); + $this->docker_compose = Yaml::dump($finalServices, 10, 2); $this->save(); $this->saveComposeConfigs(); return collect([]); diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index adf1761f1..dfa4c1788 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -147,12 +147,11 @@ function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'applica } return $labels; } -function fqdnLabelsForTraefik(Collection $domains, bool $is_force_https_enabled, $onlyPort = null) +function fqdnLabelsForTraefik($uuid, Collection $domains, bool $is_force_https_enabled, $onlyPort = null) { $labels = collect([]); $labels->push('traefik.enable=true'); foreach ($domains as $domain) { - $uuid = (string)new Cuid2(7); $url = Url::fromString($domain); $host = $url->getHost(); $path = $url->getPath(); @@ -205,20 +204,21 @@ function fqdnLabelsForTraefik(Collection $domains, bool $is_force_https_enabled, return $labels; } -function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null, $ports): array +function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null): array { + $ports = $application->settings->is_static ? [80] : $application->ports_exposes_array; $onlyPort = null; if (count($ports) === 1) { $onlyPort = $ports[0]; } $pull_request_id = data_get($preview, 'pull_request_id', 0); - $container_name = generateApplicationContainerName($application, $pull_request_id); + // $container_name = generateApplicationContainerName($application, $pull_request_id); $appId = $application->id; if ($pull_request_id !== 0 && $pull_request_id !== null) { $appId = $appId . '-pr-' . $pull_request_id; } $labels = collect([]); - $labels = $labels->merge(defaultLabels($appId, $container_name, $pull_request_id)); + $labels = $labels->merge(defaultLabels($appId, $application->uuid, $pull_request_id)); if ($application->fqdn) { if ($pull_request_id !== 0) { $domains = Str::of(data_get($preview, 'fqdn'))->explode(','); @@ -226,7 +226,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview $domains = Str::of(data_get($application, 'fqdn'))->explode(','); } // Add Traefik labels no matter which proxy is selected - $labels = $labels->merge(fqdnLabelsForTraefik($domains, $application->settings->is_force_https_enabled,$onlyPort)); + $labels = $labels->merge(fqdnLabelsForTraefik($application->uuid, $domains, $application->settings->is_force_https_enabled, $onlyPort)); } return $labels->all(); } diff --git a/database/migrations/2023_10_18_072519_add_custom_labels_applications_table.php b/database/migrations/2023_10_18_072519_add_custom_labels_applications_table.php new file mode 100644 index 000000000..f993e35ee --- /dev/null +++ b/database/migrations/2023_10_18_072519_add_custom_labels_applications_table.php @@ -0,0 +1,28 @@ +text('custom_labels')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('applications', function (Blueprint $table) { + $table->dropColumn('custom_labels'); + }); + } +}; diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index 2962cdaa9..b554b8ff5 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -93,6 +93,12 @@ + @if ($labelsChanged) + + @else + + @endif + Reset to Default Labels

Advanced