mirror of
https://github.com/tiennm99/coolify.git
synced 2026-09-05 08:17:27 +00:00
feat(backups): support scheduled backups for application storage targets
Add polymorphic volume backup scheduling for persistent volumes and directories, expose schedule management via API, and reorganize backup configuration and execution views.
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Livewire\Project\Service;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\LocalFileVolume;
|
||||
use App\Models\ScheduledVolumeBackup;
|
||||
use App\Models\ServiceApplication;
|
||||
use App\Models\ServiceDatabase;
|
||||
use App\Models\StandaloneClickhouse;
|
||||
@@ -15,6 +16,7 @@ use App\Models\StandaloneMysql;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use App\Models\StandaloneRedis;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Attributes\On;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -34,6 +36,10 @@ class FileStorage extends Component
|
||||
|
||||
public bool $isReadOnly = false;
|
||||
|
||||
public bool $hasEnabledBackup = false;
|
||||
|
||||
public ?string $backupUrl = null;
|
||||
|
||||
#[Validate(['nullable'])]
|
||||
public ?string $content = null;
|
||||
|
||||
@@ -65,6 +71,36 @@ class FileStorage extends Component
|
||||
|
||||
$this->isReadOnly = $this->fileStorage->shouldBeReadOnlyInUI() || $this->fileStorage->is_too_large;
|
||||
$this->syncData();
|
||||
$this->refreshBackupStatus();
|
||||
}
|
||||
|
||||
#[On('refreshVolumeBackups')]
|
||||
public function refreshBackupStatus(): void
|
||||
{
|
||||
$backup = $this->fileStorage->is_directory
|
||||
? $this->fileStorage->scheduledBackups()->first()
|
||||
: null;
|
||||
|
||||
$this->hasEnabledBackup = $backup?->enabled ?? false;
|
||||
$this->backupUrl = null;
|
||||
|
||||
if (! $this->hasEnabledBackup || ! $this->resource instanceof Application) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parameters = [
|
||||
'project_uuid' => $this->resource->project()->uuid,
|
||||
'environment_uuid' => $this->resource->environment->uuid,
|
||||
'application_uuid' => $this->resource->uuid,
|
||||
];
|
||||
$hasOtherBackups = ScheduledVolumeBackup::query()
|
||||
->forApplication($this->resource)
|
||||
->where('id', '!=', $backup->id)
|
||||
->exists();
|
||||
|
||||
$this->backupUrl = $hasOtherBackups
|
||||
? route('project.application.backup.index', [...$parameters, 'search' => $this->fileStorage->fs_path])
|
||||
: route('project.application.backup.show', [...$parameters, 'backup_uuid' => $backup->uuid]);
|
||||
}
|
||||
|
||||
public function syncData(bool $toModel = false): void
|
||||
@@ -135,6 +171,10 @@ class FileStorage extends Component
|
||||
try {
|
||||
$this->authorize('update', $this->resource);
|
||||
|
||||
if ($this->fileStorage->scheduledBackups()->exists()) {
|
||||
throw new \RuntimeException('Delete this directory backup schedule and its archives before converting it to a file.');
|
||||
}
|
||||
|
||||
if ($this->fileStorage->is_host_file) {
|
||||
throw new \Exception('Host file mounts are bind-only and cannot be converted.');
|
||||
}
|
||||
@@ -162,6 +202,12 @@ class FileStorage extends Component
|
||||
return 'The provided password is incorrect.';
|
||||
}
|
||||
|
||||
if ($this->fileStorage->scheduledBackups()->exists()) {
|
||||
$this->dispatch('error', 'Delete this directory backup schedule and its archives before deleting the directory.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$message = 'File deleted.';
|
||||
if ($this->fileStorage->is_directory) {
|
||||
@@ -174,6 +220,7 @@ class FileStorage extends Component
|
||||
$this->fileStorage->deleteStorageOnServer();
|
||||
}
|
||||
$this->fileStorage->delete();
|
||||
$this->dispatch('configurationChanged');
|
||||
$this->dispatch('success', $message);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
||||
Reference in New Issue
Block a user