feat(backup): add disable local backup option and related logic for S3 uploads
This commit is contained in:
@@ -351,6 +351,12 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$size = $this->calculate_size();
|
||||
if ($this->backup->save_s3) {
|
||||
$this->upload_to_s3();
|
||||
|
||||
// If local backup is disabled, delete the local file immediately after S3 upload
|
||||
if ($this->backup->disable_local_backup) {
|
||||
deleteBackupsLocally($this->backup_location, $this->server);
|
||||
$this->add_to_backup_output('Local backup file deleted after S3 upload (disable_local_backup enabled).');
|
||||
}
|
||||
}
|
||||
|
||||
$this->team->notify(new BackupSuccess($this->backup, $this->database, $database));
|
||||
|
@@ -64,6 +64,9 @@ class BackupEdit extends Component
|
||||
#[Validate(['required', 'boolean'])]
|
||||
public bool $saveS3 = false;
|
||||
|
||||
#[Validate(['required', 'boolean'])]
|
||||
public bool $disableLocalBackup = false;
|
||||
|
||||
#[Validate(['nullable', 'integer'])]
|
||||
public ?int $s3StorageId = 1;
|
||||
|
||||
@@ -98,6 +101,7 @@ class BackupEdit extends Component
|
||||
$this->backup->database_backup_retention_days_s3 = $this->databaseBackupRetentionDaysS3;
|
||||
$this->backup->database_backup_retention_max_storage_s3 = $this->databaseBackupRetentionMaxStorageS3;
|
||||
$this->backup->save_s3 = $this->saveS3;
|
||||
$this->backup->disable_local_backup = $this->disableLocalBackup;
|
||||
$this->backup->s3_storage_id = $this->s3StorageId;
|
||||
$this->backup->databases_to_backup = $this->databasesToBackup;
|
||||
$this->backup->dump_all = $this->dumpAll;
|
||||
@@ -115,6 +119,7 @@ class BackupEdit extends Component
|
||||
$this->databaseBackupRetentionDaysS3 = $this->backup->database_backup_retention_days_s3;
|
||||
$this->databaseBackupRetentionMaxStorageS3 = $this->backup->database_backup_retention_max_storage_s3;
|
||||
$this->saveS3 = $this->backup->save_s3;
|
||||
$this->disableLocalBackup = $this->backup->disable_local_backup ?? false;
|
||||
$this->s3StorageId = $this->backup->s3_storage_id;
|
||||
$this->databasesToBackup = $this->backup->databases_to_backup;
|
||||
$this->dumpAll = $this->backup->dump_all;
|
||||
@@ -193,6 +198,12 @@ class BackupEdit extends Component
|
||||
if (! is_numeric($this->backup->s3_storage_id)) {
|
||||
$this->backup->s3_storage_id = null;
|
||||
}
|
||||
|
||||
// Validate that disable_local_backup can only be true when S3 backup is enabled
|
||||
if ($this->backup->disable_local_backup && ! $this->backup->save_s3) {
|
||||
throw new \Exception('Local backup can only be disabled when S3 backup is enabled.');
|
||||
}
|
||||
|
||||
$isValid = validate_cron_expression($this->backup->frequency);
|
||||
if (! $isValid) {
|
||||
throw new \Exception('Invalid Cron / Human expression');
|
||||
|
@@ -237,11 +237,18 @@ function removeOldBackups($backup): void
|
||||
{
|
||||
try {
|
||||
if ($backup->executions) {
|
||||
$localBackupsToDelete = deleteOldBackupsLocally($backup);
|
||||
if ($localBackupsToDelete->isNotEmpty()) {
|
||||
// If local backup is disabled, mark all executions as having local storage deleted
|
||||
if ($backup->disable_local_backup && $backup->save_s3) {
|
||||
$backup->executions()
|
||||
->whereIn('id', $localBackupsToDelete->pluck('id'))
|
||||
->where('local_storage_deleted', false)
|
||||
->update(['local_storage_deleted' => true]);
|
||||
} else {
|
||||
$localBackupsToDelete = deleteOldBackupsLocally($backup);
|
||||
if ($localBackupsToDelete->isNotEmpty()) {
|
||||
$backup->executions()
|
||||
->whereIn('id', $localBackupsToDelete->pluck('id'))
|
||||
->update(['local_storage_deleted' => true]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,10 +261,18 @@ function removeOldBackups($backup): void
|
||||
}
|
||||
}
|
||||
|
||||
$backup->executions()
|
||||
->where('local_storage_deleted', true)
|
||||
->where('s3_storage_deleted', true)
|
||||
->delete();
|
||||
// Delete executions where both local and S3 storage are marked as deleted
|
||||
// or where only S3 is enabled and S3 storage is deleted
|
||||
if ($backup->disable_local_backup && $backup->save_s3) {
|
||||
$backup->executions()
|
||||
->where('s3_storage_deleted', true)
|
||||
->delete();
|
||||
} else {
|
||||
$backup->executions()
|
||||
->where('local_storage_deleted', true)
|
||||
->where('s3_storage_deleted', true)
|
||||
->delete();
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
|
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('scheduled_database_backups', function (Blueprint $table) {
|
||||
$table->boolean('disable_local_backup')->default(false)->after('save_s3');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('scheduled_database_backups', function (Blueprint $table) {
|
||||
$table->dropColumn('disable_local_backup');
|
||||
});
|
||||
}
|
||||
};
|
@@ -18,7 +18,7 @@
|
||||
shortConfirmationLabel="Database Name" />
|
||||
@endif
|
||||
</div>
|
||||
<div class="w-48 pb-2">
|
||||
<div class="w-64 pb-2">
|
||||
<x-forms.checkbox instantSave label="Backup Enabled" id="backupEnabled" />
|
||||
@if ($s3s->count() > 0)
|
||||
<x-forms.checkbox instantSave label="S3 Enabled" id="saveS3" />
|
||||
@@ -26,11 +26,18 @@
|
||||
<x-forms.checkbox instantSave helper="No validated S3 storage available." label="S3 Enabled" id="saveS3"
|
||||
disabled />
|
||||
@endif
|
||||
@if ($backup->save_s3)
|
||||
<x-forms.checkbox instantSave label="Disable Local Backup" id="disableLocalBackup"
|
||||
helper="When enabled, backup files will be deleted from local storage immediately after uploading to S3. This requires S3 backup to be enabled." />
|
||||
@else
|
||||
<x-forms.checkbox disabled label="Disable Local Backup" id="disableLocalBackup"
|
||||
helper="When enabled, backup files will be deleted from local storage immediately after uploading to S3. This requires S3 backup to be enabled." />
|
||||
@endif
|
||||
</div>
|
||||
@if ($backup->save_s3)
|
||||
<div class="pb-6">
|
||||
<x-forms.select id="s3StorageId" label="S3 Storage" required>
|
||||
<option value="default">Select a S3 storage</option>
|
||||
<option value="default" disabled>Select a S3 storage</option>
|
||||
@foreach ($s3s as $s3)
|
||||
<option value="{{ $s3->id }}">{{ $s3->name }}</option>
|
||||
@endforeach
|
||||
@@ -77,7 +84,7 @@
|
||||
<x-forms.input label="Frequency" id="frequency" />
|
||||
<x-forms.input label="Timezone" id="timezone" disabled
|
||||
helper="The timezone of the server where the backup is scheduled to run (if not set, the instance timezone will be used)" />
|
||||
<x-forms.input label="Timeout" id="timeout" helper="The timeout of the backup job in seconds."/>
|
||||
<x-forms.input label="Timeout" id="timeout" helper="The timeout of the backup job in seconds." />
|
||||
</div>
|
||||
|
||||
<h3 class="mt-6 mb-2 text-lg font-medium">Backup Retention Settings</h3>
|
||||
|
Reference in New Issue
Block a user