mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-15 20:15:45 +00:00
fix(backup): throw explicit error when S3 storage missing or deleted (#9038)
This commit is contained in:
11 files changed
+393
-49
No files matched your search
@@ -625,10 +625,16 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
private function upload_to_s3(): void
|
||||
{
|
||||
if (is_null($this->s3)) {
|
||||
$this->backup->update([
|
||||
'save_s3' => false,
|
||||
's3_storage_id' => null,
|
||||
]);
|
||||
|
||||
throw new \Exception('S3 storage configuration is missing or has been deleted (S3 storage ID: '.($this->backup->s3_storage_id ?? 'null').'). S3 backup has been disabled for this schedule.');
|
||||
}
|
||||
|
||||
try {
|
||||
if (is_null($this->s3)) {
|
||||
return;
|
||||
}
|
||||
$key = $this->s3->key;
|
||||
$secret = $this->s3->secret;
|
||||
// $region = $this->s3->region;
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Models\S3Storage;
|
||||
use App\Support\ValidationPatterns;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\On;
|
||||
use Livewire\Component;
|
||||
|
||||
class Form extends Component
|
||||
@@ -131,19 +132,7 @@ class Form extends Component
|
||||
}
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
try {
|
||||
$this->authorize('delete', $this->storage);
|
||||
|
||||
$this->storage->delete();
|
||||
|
||||
return redirect()->route('storage.index');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
#[On('submitStorage')]
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Storage;
|
||||
|
||||
use App\Models\S3Storage;
|
||||
use App\Models\ScheduledDatabaseBackup;
|
||||
use Livewire\Component;
|
||||
|
||||
class Resources extends Component
|
||||
{
|
||||
public S3Storage $storage;
|
||||
|
||||
public array $selectedStorages = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$backups = ScheduledDatabaseBackup::where('s3_storage_id', $this->storage->id)
|
||||
->where('save_s3', true)
|
||||
->get();
|
||||
|
||||
foreach ($backups as $backup) {
|
||||
$this->selectedStorages[$backup->id] = $this->storage->id;
|
||||
}
|
||||
}
|
||||
|
||||
public function disableS3(int $backupId): void
|
||||
{
|
||||
$backup = ScheduledDatabaseBackup::findOrFail($backupId);
|
||||
|
||||
$backup->update([
|
||||
'save_s3' => false,
|
||||
's3_storage_id' => null,
|
||||
]);
|
||||
|
||||
unset($this->selectedStorages[$backupId]);
|
||||
|
||||
$this->dispatch('success', 'S3 disabled.', 'S3 backup has been disabled for this schedule.');
|
||||
}
|
||||
|
||||
public function moveBackup(int $backupId): void
|
||||
{
|
||||
$backup = ScheduledDatabaseBackup::findOrFail($backupId);
|
||||
$newStorageId = $this->selectedStorages[$backupId] ?? null;
|
||||
|
||||
if (! $newStorageId || (int) $newStorageId === $this->storage->id) {
|
||||
$this->dispatch('error', 'No change.', 'The backup is already using this storage.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$newStorage = S3Storage::where('id', $newStorageId)
|
||||
->where('team_id', $this->storage->team_id)
|
||||
->first();
|
||||
|
||||
if (! $newStorage) {
|
||||
$this->dispatch('error', 'Storage not found.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$backup->update(['s3_storage_id' => $newStorage->id]);
|
||||
|
||||
unset($this->selectedStorages[$backupId]);
|
||||
|
||||
$this->dispatch('success', 'Backup moved.', "Moved to {$newStorage->name}.");
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
$backups = ScheduledDatabaseBackup::where('s3_storage_id', $this->storage->id)
|
||||
->where('save_s3', true)
|
||||
->with('database')
|
||||
->get()
|
||||
->groupBy(fn ($backup) => $backup->database_type.'-'.$backup->database_id);
|
||||
|
||||
$allStorages = S3Storage::where('team_id', $this->storage->team_id)
|
||||
->orderBy('name')
|
||||
->get(['id', 'name', 'is_usable']);
|
||||
|
||||
return view('livewire.storage.resources', [
|
||||
'groupedBackups' => $backups,
|
||||
'allStorages' => $allStorages,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Livewire\Storage;
|
||||
|
||||
use App\Models\S3Storage;
|
||||
use App\Models\ScheduledDatabaseBackup;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -12,6 +13,10 @@ class Show extends Component
|
||||
|
||||
public $storage = null;
|
||||
|
||||
public string $currentRoute = '';
|
||||
|
||||
public int $backupCount = 0;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->storage = S3Storage::ownedByCurrentTeam()->whereUuid(request()->storage_uuid)->first();
|
||||
@@ -19,6 +24,21 @@ class Show extends Component
|
||||
abort(404);
|
||||
}
|
||||
$this->authorize('view', $this->storage);
|
||||
$this->currentRoute = request()->route()->getName();
|
||||
$this->backupCount = ScheduledDatabaseBackup::where('s3_storage_id', $this->storage->id)->count();
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
try {
|
||||
$this->authorize('delete', $this->storage);
|
||||
|
||||
$this->storage->delete();
|
||||
|
||||
return redirect()->route('storage.index');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
||||
@@ -40,6 +40,13 @@ class S3Storage extends BaseModel
|
||||
$storage->secret = trim($storage->secret);
|
||||
}
|
||||
});
|
||||
|
||||
static::deleting(function (S3Storage $storage) {
|
||||
ScheduledDatabaseBackup::where('s3_storage_id', $storage->id)->update([
|
||||
'save_s3' => false,
|
||||
's3_storage_id' => null,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public static function ownedByCurrentTeam(array $select = ['*'])
|
||||
@@ -59,6 +66,11 @@ class S3Storage extends BaseModel
|
||||
return $this->belongsTo(Team::class);
|
||||
}
|
||||
|
||||
public function scheduledBackups()
|
||||
{
|
||||
return $this->hasMany(ScheduledDatabaseBackup::class, 's3_storage_id');
|
||||
}
|
||||
|
||||
public function awsUrl()
|
||||
{
|
||||
return "{$this->endpoint}/{$this->bucket}";
|
||||
|
||||
Reference in new issue
Block a user