From 85b33a60b3d14fe7c9a2a87058459a8cd19f4ef3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 15 Apr 2024 19:47:17 +0200 Subject: [PATCH] feat: can edit file/dir volumes from ui in compose based apps --- app/Jobs/ServerFilesFromServerJob.php | 5 ++- app/Livewire/Project/Application/General.php | 34 +++++++++++++++- app/Livewire/Project/Service/FileStorage.php | 40 ++++++++++++++++++- app/Livewire/Project/Service/Storage.php | 13 ++++-- app/Livewire/Project/Shared/Storages/All.php | 2 +- app/Models/Application.php | 5 +++ app/Models/LocalFileVolume.php | 21 +++++++++- app/Providers/EventServiceProvider.php | 4 +- bootstrap/helpers/services.php | 14 ++++--- .../application/configuration.blade.php | 2 +- .../project/service/file-storage.blade.php | 37 ++++++++++++----- .../project/service/storage.blade.php | 40 +++++++++++-------- .../shared/environment-variable/all.blade.php | 2 +- 13 files changed, 171 insertions(+), 48 deletions(-) diff --git a/app/Jobs/ServerFilesFromServerJob.php b/app/Jobs/ServerFilesFromServerJob.php index b195e2b6d..978a3dc19 100644 --- a/app/Jobs/ServerFilesFromServerJob.php +++ b/app/Jobs/ServerFilesFromServerJob.php @@ -2,6 +2,7 @@ namespace App\Jobs; +use App\Models\Application; use App\Models\ServiceApplication; use App\Models\ServiceDatabase; use Illuminate\Bus\Queueable; @@ -16,11 +17,11 @@ class ServerFilesFromServerJob implements ShouldQueue, ShouldBeEncrypted use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public function __construct(public ServiceApplication|ServiceDatabase $service) + public function __construct(public ServiceApplication|ServiceDatabase|Application $resource) { } public function handle() { - $this->service->getFilesFromServer(isInit: true); + $this->resource->getFilesFromServer(isInit: true); } } diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index f10da3563..2468112b8 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -3,6 +3,7 @@ namespace App\Livewire\Project\Application; use App\Models\Application; +use App\Models\LocalFileVolume; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Livewire\Component; @@ -124,7 +125,7 @@ public function mount() } $this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : []; $this->ports_exposes = $this->application->ports_exposes; - $this->customLabels = $this->application->parseContainerLabels(); + $this->customLabels = $this->application->parseContainerLabels(); if (!$this->customLabels && $this->application->destination->server->proxyType() !== 'NONE') { $this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n"); $this->application->custom_labels = base64_encode($this->customLabels); @@ -156,8 +157,36 @@ public function loadComposeFile($isInit = false) return; } ['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation, 'initialDockerComposePrLocation' => $this->initialDockerComposePrLocation] = $this->application->loadComposeFile($isInit); + $compose = $this->application->parseCompose(); + $services = data_get($compose, 'services'); + if ($services) { + $volumes = collect($services)->map(function ($service) { + return data_get($service, 'volumes'); + })->flatten()->filter(function ($volume) { + return str($volume)->startsWith('/data/coolify'); + })->unique()->values(); + foreach ($volumes as $volume) { + $source = Str::of($volume)->before(':'); + $target = Str::of($volume)->after(':')->beforeLast(':'); + + LocalFileVolume::updateOrCreate( + [ + 'mount_path' => $target, + 'resource_id' => $this->application->id, + 'resource_type' => get_class($this->application) + ], + [ + 'fs_path' => $source, + 'mount_path' => $target, + 'resource_id' => $this->application->id, + 'resource_type' => get_class($this->application) + ] + ); + } + } $this->dispatch('success', 'Docker compose file loaded.'); $this->dispatch('compose_loaded'); + $this->dispatch('refreshStorages'); } catch (\Throwable $e) { $this->application->docker_compose_location = $this->initialDockerComposeLocation; $this->application->docker_compose_pr_location = $this->initialDockerComposePrLocation; @@ -183,7 +212,8 @@ public function updatedApplicationBaseDirectory() $this->loadComposeFile(); } } - public function updatedApplicationFqdn() { + public function updatedApplicationFqdn() + { $this->resetDefaultLabels(); } public function updatedApplicationBuildPack() diff --git a/app/Livewire/Project/Service/FileStorage.php b/app/Livewire/Project/Service/FileStorage.php index 0077f5cda..c26e19554 100644 --- a/app/Livewire/Project/Service/FileStorage.php +++ b/app/Livewire/Project/Service/FileStorage.php @@ -2,6 +2,7 @@ namespace App\Livewire\Project\Service; +use App\Models\Application; use App\Models\LocalFileVolume; use App\Models\ServiceApplication; use App\Models\ServiceDatabase; @@ -12,7 +13,7 @@ class FileStorage extends Component { public LocalFileVolume $fileStorage; - public ServiceApplication|ServiceDatabase|StandaloneClickhouse $resource; + public ServiceApplication|ServiceDatabase|StandaloneClickhouse|Application $resource; public string $fs_path; public ?string $workdir = null; @@ -33,6 +34,43 @@ public function mount() $this->fs_path = $this->fileStorage->fs_path; } } + public function convertToDirectory() { + try { + $this->fileStorage->deleteStorageOnServer(); + $this->fileStorage->is_directory = true; + $this->fileStorage->content = null; + $this->fileStorage->save(); + $this->fileStorage->saveStorageOnServer(); + } catch (\Throwable $e) { + return handleError($e, $this); + } finally { + $this->dispatch('storagesChanged'); + } + } + public function convertToFile() { + try { + $this->fileStorage->deleteStorageOnServer(); + $this->fileStorage->is_directory = false; + $this->fileStorage->content = null; + $this->fileStorage->save(); + $this->fileStorage->saveStorageOnServer(); + } catch (\Throwable $e) { + return handleError($e, $this); + } finally { + $this->dispatch('storagesChanged'); + } + } + public function delete() { + try { + $this->fileStorage->deleteStorageOnServer(); + $this->fileStorage->delete(); + $this->dispatch('success', 'File deleted.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } finally { + $this->dispatch('storagesChanged'); + } + } public function submit() { $original = $this->fileStorage->getOriginal(); diff --git a/app/Livewire/Project/Service/Storage.php b/app/Livewire/Project/Service/Storage.php index 0accde787..77df92c6f 100644 --- a/app/Livewire/Project/Service/Storage.php +++ b/app/Livewire/Project/Service/Storage.php @@ -7,12 +7,13 @@ class Storage extends Component { - protected $listeners = ['addNewVolume']; public $resource; - - public function render() + public function getListeners() { - return view('livewire.project.service.storage'); + return [ + 'addNewVolume', + 'storagesChanged'=> '$refresh' + ]; } public function addNewVolume($data) { @@ -32,4 +33,8 @@ public function addNewVolume($data) return handleError($e, $this); } } + public function render() + { + return view('livewire.project.service.storage'); + } } diff --git a/app/Livewire/Project/Shared/Storages/All.php b/app/Livewire/Project/Shared/Storages/All.php index a17153343..18060da2a 100644 --- a/app/Livewire/Project/Shared/Storages/All.php +++ b/app/Livewire/Project/Shared/Storages/All.php @@ -7,7 +7,7 @@ class All extends Component { public $resource; - protected $listeners = ['refreshStorages']; + protected $listeners = ['refreshStorages', 'storagesChanged' => '$refresh']; public function refreshStorages() { diff --git a/app/Models/Application.php b/app/Models/Application.php index d1bded126..4c2d23d8f 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -954,4 +954,9 @@ public function isWatchPathsTriggered(Collection $modified_files): bool }); return $matches->count() > 0; } + + public function getFilesFromServer(bool $isInit = false) + { + getFilesystemVolumesFromServer($this, $isInit); + } } diff --git a/app/Models/LocalFileVolume.php b/app/Models/LocalFileVolume.php index 4cf99a665..25cb6bee7 100644 --- a/app/Models/LocalFileVolume.php +++ b/app/Models/LocalFileVolume.php @@ -20,6 +20,26 @@ public function service() { return $this->morphTo('resource'); } + public function deleteStorageOnServer() + { + $isService = data_get($this->resource, 'service'); + if ($isService) { + $workdir = $this->resource->service->workdir(); + $server = $this->resource->service->server; + } else { + $workdir = $this->resource->workdir(); + $server = $this->resource->destination->server; + } + $commands = collect([ + "cd $workdir" + ]); + $fs_path = data_get($this, 'fs_path'); + if ($fs_path && $fs_path != '/' && $fs_path != '.' && $fs_path != '..') { + $commands->push("rm -rf $fs_path"); + } + ray($commands); + return instant_remote_process($commands, $server); + } public function saveStorageOnServer() { $isService = data_get($this->resource, 'service'); @@ -71,7 +91,6 @@ public function saveStorageOnServer() if ($chmod) { $commands->push("chmod $chmod $path"); } - } } else if ($isDir == 'NOK' && $fileVolume->is_directory) { $commands->push("mkdir -p $path > /dev/null 2>&1 || true"); diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index a6ded1dc7..a1b6beb6e 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -20,9 +20,9 @@ class EventServiceProvider extends ServiceProvider MaintenanceModeDisabledNotification::class, ], \SocialiteProviders\Manager\SocialiteWasCalled::class => [ - \SocialiteProviders\Azure\AzureExtendSocialite::class.'@handle', + \SocialiteProviders\Azure\AzureExtendSocialite::class . '@handle', ], - ProxyStarted::class => [ + ProxyStarted::class => [ ProxyStartedNotification::class, ], ]; diff --git a/bootstrap/helpers/services.php b/bootstrap/helpers/services.php index b690659dd..e6f108223 100644 --- a/bootstrap/helpers/services.php +++ b/bootstrap/helpers/services.php @@ -1,7 +1,7 @@ replaceFirst('$', '')->replaceFirst('{', '')->replaceLast('}', ''); } -function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase $oneService, bool $isInit = false) +function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase|Application $oneService, bool $isInit = false) { - // TODO: make this async try { - $workdir = $oneService->service->workdir(); - $server = $oneService->service->server; + if ($oneService->getMorphClass() === 'App\Models\Application') { + $workdir = $oneService->workdir(); + $server = $oneService->destination->server; + } else{ + $workdir = $oneService->service->workdir(); + $server = $oneService->service->server; + } $fileVolumes = $oneService->fileStorages()->get(); $commands = collect([ "mkdir -p $workdir > /dev/null 2>&1 || true", diff --git a/resources/views/livewire/project/application/configuration.blade.php b/resources/views/livewire/project/application/configuration.blade.php index 102f8681b..8767b101c 100644 --- a/resources/views/livewire/project/application/configuration.blade.php +++ b/resources/views/livewire/project/application/configuration.blade.php @@ -19,7 +19,7 @@ href="#">Environment Variables @endif - @if ($application->build_pack !== 'static' && $application->build_pack !== 'dockercompose') + @if ($application->build_pack !== 'static') Storages diff --git a/resources/views/livewire/project/service/file-storage.blade.php b/resources/views/livewire/project/service/file-storage.blade.php index 116d8a06a..07e219b10 100644 --- a/resources/views/livewire/project/service/file-storage.blade.php +++ b/resources/views/livewire/project/service/file-storage.blade.php @@ -1,17 +1,32 @@ -
+

{{ data_get($resource, 'name', 'unknown') }}

{{ $workdir }}{{ $fs_path }} -> {{ $fileStorage->mount_path }}
+ @if ($fileStorage->is_directory) +
Directory
+ @else +
File
+ @endif
-
-
-
- -
- @if (!$fileStorage->is_directory) - - Save + +
+ @if ($fileStorage->is_directory) + + This will delete all files in this directory. It is not reversible.
Please think again. +
+ @else + + This will convert this to a directory. If it was a file, it will be deleted. It is not reversible.
Please think again. +
@endif - -
+ + This file / directory will be deleted. It is not reversible.
Please think again. +
+
+ @if (!$fileStorage->is_directory) + + Save + @endif + +
diff --git a/resources/views/livewire/project/service/storage.blade.php b/resources/views/livewire/project/service/storage.blade.php index d3498dcff..c1b12103b 100644 --- a/resources/views/livewire/project/service/storage.blade.php +++ b/resources/views/livewire/project/service/storage.blade.php @@ -14,25 +14,30 @@ helper="For Preview Deployments, storage has a -pr-#PRNumber in their volume name, example: -pr-1" /> - - - + @if ($resource?->build_pack !== 'dockercompose') + + + + @endif
Persistent storage to preserve data between deployments.
+ @if ($resource?->build_pack === 'dockercompose') + Please modify storage layout in your Docker Compose + file or reload the compose file to reread the storage layout. + @endif @if ($resource->persistentStorages()->get()->count() === 0 && $resource->fileStorages()->get()->count() == 0) -
No storage found.
- @else - @if ($resource->persistentStorages()->get()->count() > 0) - - @endif - @if ($resource->fileStorages()->get()->count() > 0) -
- @foreach ($resource->fileStorages()->get()->sort() as $fileStorage) - - @endforeach -
- @endif +
No storage found.
+ @endif + @if ($resource->persistentStorages()->get()->count() > 0) + + @endif + @if ($resource->fileStorages()->get()->count() > 0) +
+ @foreach ($resource->fileStorages()->get()->sort() as $fileStorage) + + @endforeach +
@endif @else @if ($resource->persistentStorages()->get()->count() > 0) @@ -44,7 +49,8 @@ @if ($resource->fileStorages()->get()->count() > 0)
@foreach ($resource->fileStorages()->get()->sort() as $fileStorage) - + @endforeach
@endif diff --git a/resources/views/livewire/project/shared/environment-variable/all.blade.php b/resources/views/livewire/project/shared/environment-variable/all.blade.php index c6a0a0707..06df0871c 100644 --- a/resources/views/livewire/project/shared/environment-variable/all.blade.php +++ b/resources/views/livewire/project/shared/environment-variable/all.blade.php @@ -12,7 +12,7 @@
Environment variables (secrets) for this resource.
@if ($resource->type() === 'service' || $resource?->build_pack === 'dockercompose') -
Hardcoded variables are not shown here.
+
Hardcoded variables are not shown here.
@endif @if ($view === 'normal')