mirror of
https://github.com/cupcakearmy/coolify.git
synced 2024-10-22 08:04:19 +02:00
fix: file storages (dir/file mount) handled properly
This commit is contained in:
parent
8133a8b770
commit
ea5101c814
32
app/Events/FileStorageChanged.php
Normal file
32
app/Events/FileStorageChanged.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class FileStorageChanged implements ShouldBroadcast
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $teamId;
|
||||
|
||||
public function __construct($teamId = null)
|
||||
{
|
||||
ray($teamId);
|
||||
if (is_null($teamId)) {
|
||||
throw new \Exception('Team id is null');
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
return [
|
||||
new PrivateChannel("team.{$this->teamId}"),
|
||||
];
|
||||
}
|
||||
}
|
@ -214,7 +214,7 @@ public function loadComposeFile($isInit = false)
|
||||
}
|
||||
$this->dispatch('success', 'Docker compose file loaded.');
|
||||
$this->dispatch('compose_loaded');
|
||||
$this->dispatch('refresh_storages');
|
||||
$this->dispatch('refreshStorages');
|
||||
$this->dispatch('refreshEnvs');
|
||||
} catch (\Throwable $e) {
|
||||
$this->application->docker_compose_location = $this->initialDockerComposeLocation;
|
||||
|
@ -26,6 +26,8 @@ class FileStorage extends Component
|
||||
|
||||
public ?string $workdir = null;
|
||||
|
||||
public bool $permanently_delete = true;
|
||||
|
||||
protected $rules = [
|
||||
'fileStorage.is_directory' => 'required',
|
||||
'fileStorage.fs_path' => 'required',
|
||||
@ -56,7 +58,7 @@ public function convertToDirectory()
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh_storages');
|
||||
$this->dispatch('refreshStorages');
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,20 +73,27 @@ public function convertToFile()
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh_storages');
|
||||
$this->dispatch('refreshStorages');
|
||||
}
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
try {
|
||||
$this->fileStorage->deleteStorageOnServer();
|
||||
$message = 'File deleted.';
|
||||
if ($this->fileStorage->is_directory) {
|
||||
$message = 'Directory deleted.';
|
||||
}
|
||||
if ($this->permanently_delete) {
|
||||
$message = 'Directory deleted from the server.';
|
||||
$this->fileStorage->deleteStorageOnServer();
|
||||
}
|
||||
$this->fileStorage->delete();
|
||||
$this->dispatch('success', 'File deleted.');
|
||||
$this->dispatch('success', $message);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
$this->dispatch('refresh_storages');
|
||||
$this->dispatch('refreshStorages');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,14 +9,35 @@ class Storage extends Component
|
||||
{
|
||||
public $resource;
|
||||
|
||||
public $fileStorage;
|
||||
|
||||
public function getListeners()
|
||||
{
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
return [
|
||||
"echo-private:team.{$teamId},FileStorageChanged" => 'refreshStoragesFromEvent',
|
||||
'refreshStorages' => '$refresh',
|
||||
'addNewVolume',
|
||||
'refresh_storages' => '$refresh',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->refreshStorages();
|
||||
}
|
||||
|
||||
public function refreshStoragesFromEvent()
|
||||
{
|
||||
$this->refreshStorages();
|
||||
$this->dispatch('warning', 'File storage changed. Usually it means that the file / directory is already defined on the server, so Coolify set it up for you properly on the UI.');
|
||||
}
|
||||
|
||||
public function refreshStorages()
|
||||
{
|
||||
$this->fileStorage = $this->resource->fileStorages()->get();
|
||||
}
|
||||
|
||||
public function addNewVolume($data)
|
||||
{
|
||||
try {
|
||||
@ -30,7 +51,7 @@ public function addNewVolume($data)
|
||||
$this->resource->refresh();
|
||||
$this->dispatch('success', 'Storage added successfully');
|
||||
$this->dispatch('clearAddStorage');
|
||||
$this->dispatch('refresh_storages');
|
||||
$this->dispatch('refreshStorages');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ public function submitFileStorage()
|
||||
'resource_type' => get_class($this->resource),
|
||||
],
|
||||
);
|
||||
$this->dispatch('refresh_storages');
|
||||
$this->dispatch('refreshStorages');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
@ -123,7 +123,7 @@ public function submitFileStorageDirectory()
|
||||
'resource_type' => get_class($this->resource),
|
||||
],
|
||||
);
|
||||
$this->dispatch('refresh_storages');
|
||||
$this->dispatch('refreshStorages');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
|
@ -8,5 +8,5 @@ class All extends Component
|
||||
{
|
||||
public $resource;
|
||||
|
||||
protected $listeners = ['refresh_storages' => '$refresh'];
|
||||
protected $listeners = ['refreshStorages' => '$refresh'];
|
||||
}
|
||||
|
@ -39,6 +39,6 @@ public function submit()
|
||||
public function delete()
|
||||
{
|
||||
$this->storage->delete();
|
||||
$this->dispatch('refresh_storages');
|
||||
$this->dispatch('refreshStorages');
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Events\FileStorageChanged;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class LocalFileVolume extends BaseModel
|
||||
@ -33,16 +34,23 @@ public function deleteStorageOnServer()
|
||||
$workdir = $this->resource->workdir();
|
||||
$server = $this->resource->destination->server;
|
||||
}
|
||||
$commands = collect([
|
||||
"cd $workdir",
|
||||
]);
|
||||
$commands = collect([]);
|
||||
$fs_path = data_get($this, 'fs_path');
|
||||
$isFile = instant_remote_process(["test -f $fs_path && echo OK || echo NOK"], $server);
|
||||
$isDir = instant_remote_process(["test -d $fs_path && echo OK || echo NOK"], $server);
|
||||
if ($fs_path && $fs_path != '/' && $fs_path != '.' && $fs_path != '..') {
|
||||
$commands->push("rm -rf $fs_path");
|
||||
}
|
||||
ray($commands);
|
||||
ray($isFile, $isDir);
|
||||
if ($isFile === 'OK') {
|
||||
$commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
|
||||
|
||||
return instant_remote_process($commands, $server);
|
||||
} elseif ($isDir === 'OK') {
|
||||
$commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
|
||||
$commands->push("rmdir $fs_path > /dev/null 2>&1 || true");
|
||||
}
|
||||
}
|
||||
if ($commands->count() > 0) {
|
||||
return instant_remote_process($commands, $server);
|
||||
}
|
||||
}
|
||||
|
||||
public function saveStorageOnServer()
|
||||
@ -55,13 +63,10 @@ public function saveStorageOnServer()
|
||||
$workdir = $this->resource->workdir();
|
||||
$server = $this->resource->destination->server;
|
||||
}
|
||||
$commands = collect([
|
||||
"mkdir -p $workdir > /dev/null 2>&1 || true",
|
||||
"cd $workdir",
|
||||
]);
|
||||
$is_directory = $this->is_directory;
|
||||
if ($is_directory) {
|
||||
$commands = collect([]);
|
||||
if ($this->is_directory) {
|
||||
$commands->push("mkdir -p $this->fs_path > /dev/null 2>&1 || true");
|
||||
$commands->push("cd $workdir");
|
||||
}
|
||||
if (str($this->fs_path)->startsWith('.') || str($this->fs_path)->startsWith('/') || str($this->fs_path)->startsWith('~')) {
|
||||
$parent_dir = str($this->fs_path)->beforeLast('/');
|
||||
@ -79,8 +84,11 @@ public function saveStorageOnServer()
|
||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
||||
$content = instant_remote_process(["cat $path"], $server, false);
|
||||
$fileVolume->is_directory = false;
|
||||
$fileVolume->content = $content;
|
||||
$fileVolume->save();
|
||||
FileStorageChanged::dispatch(data_get($server, 'team_id'));
|
||||
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
|
||||
} elseif ($isDir == 'OK' && ! $fileVolume->is_directory) {
|
||||
$fileVolume->is_directory = true;
|
||||
|
@ -14,16 +14,30 @@
|
||||
<div class="flex gap-2">
|
||||
@if ($fileStorage->is_directory)
|
||||
<x-modal-confirmation action="convertToFile" buttonTitle="Convert to file">
|
||||
This will delete all files in this directory. It is not reversible. <br>Please think again.
|
||||
<div>This will delete all files in this directory. It is not reversible. <strong
|
||||
class="text-error">Please think
|
||||
again.</strong><br><br></div>
|
||||
</x-modal-confirmation>
|
||||
@else
|
||||
<x-modal-confirmation action="convertToDirectory" buttonTitle="Convert to directory">
|
||||
This will convert this to a directory. If it was a file, it will be deleted. It is not reversible.
|
||||
<br>Please think again.
|
||||
<div>This will delete the file and make a directory instead. It is not reversible.
|
||||
<strong class="text-error">Please think
|
||||
again.</strong><br><br>
|
||||
</div>
|
||||
</x-modal-confirmation>
|
||||
@endif
|
||||
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
||||
This file / directory will be deleted. It is not reversible. <br>Please think again.
|
||||
<div class="px-2">This resource will be deleted. It is not reversible. <strong
|
||||
class="text-error">Please think
|
||||
again.</strong><br><br></div>
|
||||
<h4>Actions</h4>
|
||||
@if ($fileStorage->is_directory)
|
||||
<x-forms.checkbox id="permanently_delete"
|
||||
label="Permanently delete directory from the server?"></x-forms.checkbox>
|
||||
@else
|
||||
<x-forms.checkbox id="permanently_delete"
|
||||
label="Permanently delete file from the server?"></x-forms.checkbox>
|
||||
@endif
|
||||
</x-modal-confirmation>
|
||||
</div>
|
||||
@if (!$fileStorage->is_directory)
|
||||
|
@ -25,7 +25,7 @@
|
||||
<span class="dark:text-warning text-coollabs">Please modify storage layout in your Docker Compose
|
||||
file or reload the compose file to reread the storage layout.</span>
|
||||
@else
|
||||
@if ($resource->persistentStorages()->get()->count() === 0 && $resource->fileStorages()->get()->count() == 0)
|
||||
@if ($resource->persistentStorages()->get()->count() === 0 && $fileStorage->count() == 0)
|
||||
<div class="pt-4">No storage found.</div>
|
||||
@endif
|
||||
@endif
|
||||
@ -33,9 +33,9 @@
|
||||
@if ($resource->persistentStorages()->get()->count() > 0)
|
||||
<livewire:project.shared.storages.all :resource="$resource" />
|
||||
@endif
|
||||
@if ($resource->fileStorages()->get()->count() > 0)
|
||||
@if ($fileStorage->count() > 0)
|
||||
<div class="flex flex-col gap-4 pt-4">
|
||||
@foreach ($resource->fileStorages()->get()->sort() as $fileStorage)
|
||||
@foreach ($fileStorage->sort() as $fileStorage)
|
||||
<livewire:project.service.file-storage :fileStorage="$fileStorage"
|
||||
wire:key="resource-{{ $fileStorage->uuid }}" />
|
||||
@endforeach
|
||||
@ -48,9 +48,9 @@
|
||||
@if ($resource->persistentStorages()->get()->count() > 0)
|
||||
<livewire:project.shared.storages.all :resource="$resource" />
|
||||
@endif
|
||||
@if ($resource->fileStorages()->get()->count() > 0)
|
||||
@if ($fileStorage->count() > 0)
|
||||
<div class="flex flex-col gap-4 pt-4">
|
||||
@foreach ($resource->fileStorages()->get()->sort() as $fileStorage)
|
||||
@foreach ($fileStorage->sort() as $fileStorage)
|
||||
<livewire:project.service.file-storage :fileStorage="$fileStorage"
|
||||
wire:key="resource-{{ $fileStorage->uuid }}" />
|
||||
@endforeach
|
||||
|
Loading…
Reference in New Issue
Block a user